精华内容
下载资源
问答
  • 对象在信息世界中称为
    千次阅读
    2018-02-01 22:02:29

    关键词:   对象    抽象    状态    映射    静态


    • 对象和类

    对象一词,我们可能会联想到一个物体。比如一支笔,一本书,等等。他们都可以称为对象。对象其实就是现实生活中常见的事物,每个事物都可以叫做对象。反过来讲,严格的说对象不能简单的叫做事物,它是对事物的统称。这是广义的对象。


    在现实世界中,在我们人类的视角下,会对各种事物进行一个分类,比如动物类,景观类等。分类的目的是让我们更清楚的认识世界,从而管理世界,应用世界。按照对象的广义的解释,对应每个类中,类中的对象即被赋予了特殊含义,可称为狭义对象。特殊含义是指这些类中对象具有共同的特性,它们是类的实例化。 比如马是动物类的一个实例对象。 我们通常是先接触对象,然后观察它们的特点,再进行归纳总结,从而定义出对象的集合——类。
    对象的特点包括两部分:一是它的状态(基本属性);二是它的行为(方法)。我们仍然以马为例。马的性别,年龄,体形,颜色等属于它的状态,而马奔跑、吃草属于它的行为。生活中有很多这样的例子,对象无处不在。哲学家们正是最先由生活中的对象而产生思考,并进行推理和联想。


    • 从上学起,我们便要学习数学这门课。
    当你学到一定年龄,你会对数学有一个这样的认识:它好抽象!你可能会抱怨:这都是什么鬼符号?!(…4*2^(lim(lnN+3##22#))…)。 没错,数学的魅力正是在于它的抽象。它把生活中发生的事情进行(最)本质的抽象。通过抽象,数学计算中可以不必关注具体事物的状态和行为,而仅是对其抽象的东西进行运算,因为这样可以提高效率。在无数的数学运算中,必定蕴藏着某些思维方法,比如数形结合法,归纳法等。这些方法通过人类发展中的不断实践总结而形成。在本文中我们会提到这几个方法:抽象,联想,举一反三,映射。


    我们开始把视角从数学调到程序语言上,准确的讲是面向对象程序编程(OOP)。(这里主要讨论Java)
    应用之前的分析,OOP就可相当于一个虚拟世界。OOP中对象即是对现实世界对象的一个抽象,它也包括状态和行为(这里通常叫做方法)。对象属于类,是类的一个实例。Java中的类是广义的类,它不仅可以指一类具有共同特性的对象,也可以指一个要解决的问题,因为确切的说问题也可以被当作一个类。另外一个不同点是OOP中先有类,再有对象*(类中也可以无对象),而现实生活中我们总是先观察到一个对象,一般不会直接想到它是哪一类 的对象。


    • OOP中对象的状态和方法非常有趣。
    状态,也称字段,数据成员,属性等。它描述对象的属性信息。我称它为静的东西。
    方法,c/c++中也叫函数。它描述对象可以有哪些行为。我称它为动的东西。
    在一个类中,通过一些动静的结合,可以想象到从程序语言到现实世界的映射。


    类中有一个东西叫静态的(static)。如果要映射到现实世界的类,我联想到的是静态的即对应常态的。现实中一个对象常态是什么样的,就是说它经常表现出的状态和行为,区别于非常态。当然这种映射不是严格的,你可以联想到更多例子。
    类中静态常量是指在另一个类中可以直接调用类而获取静态常量(前提是非私有)。静态方法类似。
    而非静态常量指在另一个类中要想使用该类的成员和方法,必须创建一个该类的对象,然后用该对象调用其成员或方法,(通常使用对象的引用来调用)


    暂时说到这里。下次将讨论现实生活中的联系,以及在OOP中是怎样运用的。
    (我把这种从一个领域中的思维或关键字联想到另一个领域的过程叫做举一反三的广义化。)






    注释:*1(标题)。指OOP中对象,是对现实世界对象的抽象。
    *2(先有类,再有对象)。指要想创建一个对象,首先要有这个对象所属的类。

    更多相关内容
  • 吃人的那些 Java 名词:对象、引用、堆、栈

    万次阅读 多人点赞 2019-09-05 15:57:09
    作为一个有着 8 年 Java 编程经验的 IT 老兵,说起来很惭愧,我被 Java 当中的四五个名词一直困扰着:**对象、引用、堆、栈、堆栈**(栈可同堆栈,因此是四个名词,也是五个名词)。每次我看到这几个名词,都隐隐...

    作为一个有着 8 年 Java 编程经验的 IT 老兵,说起来很惭愧,我被 Java 当中的四五个名词一直困扰着:对象、引用、堆、栈、堆栈(栈可同堆栈,因此是四个名词,也是五个名词)。每次我看到这几个名词,都隐隐约约觉得自己在被一只无形的大口慢慢地吞噬,只剩下满地的衣服碎屑(为什么不是骨头,因为骨头也好吃)。

    记得中学的课本上,有一篇名为《狂人日记》课文;那时候根本理解不了鲁迅写这篇文章要表达的中心思想,只觉得满篇的“吃人”令人心情压抑;老师在讲台上慷慨激昂的讲,大多数的同学同我一样,在课本面前“痴痴”的发呆。

    十几年后,再读《狂人日记》,恍然如梦:

    鲁迅先生以狂人的口吻,再现了动乱时期下中国人的精神状态,视角新颖,文笔细腻又不乏辛辣之味。

    当时的中国,混乱成了主色调。以清廷和孔教为主的封建旧思想还在潜移默化地影响着人们的思想,与此同时以革命和新思潮为主的现代思想已经开始了对大众灵魂的洗涤和冲击。

    最近,和沉默王二技术交流群(120926808)的群友们交流后,Java 中那四五个会吃人的名词:对象、引用、堆、栈、堆栈,似乎在脑海中也清晰了起来,尽管疑惑有时候仍然会在阴云密布时跑出来——正鉴于此,这篇文章恰好做一下归纳。

    一、对象和引用

    在 Java 中,尽管一切都可以看做是对象,但计算机操作的并非对象本身,而是对象的引用。 这话乍眼一看,似懂非懂。究竟什么是对象,什么又是引用呢?

    先来看对象的定义:按照通俗的说法,每个对象都是某个类(class)的一个实例(instance)。那么,实例化的过程怎么描述呢?来看代码(类是 String):

    new String("我是对象张三");
    new String("我是对象李四");
    

    在 Java 中,实例化指的就是通过关键字“new”来创建对象的过程。以上代码在运行时就会创建两个对象——“我是对象张三"和"我是对象李四”;现在,该怎么操作他们呢?

    去过公园的同学应该会见过几个大爷,他们很有一番本领——个个都能把风筝飞得老高老高,徒留我们眼馋的份!风筝飞那么高,没办法直接用手拽着飞啊,全要靠一根长长的看不见的结实的绳子来牵引!操作 Java 对象也是这个理,得有一根绳——也就是接下来要介绍的“引用”(我们肉眼也常常看不见它)。

    String zhangsan, lisi;
    zhangsan = new String("我是对象张三");
    lisi = new String("我是对象李四");
    

    这三行代码该怎么理解呢?

    先来看第一行代码:String zhangsan, lisi;——声明了两个变量 zhangsan 和 lisi,他们的类型为 String。

    ①、歧义:zhangsan 和 lisi 此时被称为引用。

    你也许听过这样一句古文:“神之于形,犹利之于刀;未闻刀没而利存,岂容形亡而神在?”这是无神论者范缜(zhen)的名言,大致的意思就是:灵魂对于肉体来说,就像刀刃对于刀身;从没听说过刀身都没了刀刃还存在,那么怎么可能允许肉体死亡了而灵魂还在呢?

    “引用”之于对象,就好比刀刃之于刀身,对象还没有创建,又怎么存在对象的“引用”呢?

    如果 zhangsan 和 lisi 此时不能被称为“引用”,那么他们是什么呢?答案很简单,就是变量啊!(鄙人理解)

    ②、误解:zhangsan 和 lisi 此时的默认值为 null

    应该说 zhangsan 和 lisi 此时的值为 undefined——借用 JavaScript 的关键字;也就是未定义;或者应该是一个新的关键字 uninitialized——未初始化。但不管是 undefined 还是 uninitialized,都与 null 不同。

    既然没有初始化,zhangsan 和 lisi 此时就不能被使用。假如强行使用的话,编译器就会报错,提醒 zhangsan 和 lisi 还没有出生(初始化);见下图。

    如果把 zhangsan 和 lisi 初始化为 null,编译器是认可的(见下图);由此可见,zhangsan 和 lisi 此时的默认值不为 null

    再来看第二行代码:zhangsan = new String("我是对象张三");——创建“我是对象张三"的 String 类对象,并将其赋值给 zhangsan 这个变量。

    此时,zhangsan 就是"我是对象张三"的引用;“=”操作符赋予了 zhangsan 这样神圣的权利。

    第三行代码 lisi = new String("我是对象李四");和第二行代码 zhangsan = new String("我是对象张三");同理。

    现在,我可以下这样一个结论了——对象是通过 new 关键字创建的;引用是依赖于对象的;= 操作符把对象赋值给了引用

    我们再来看这样一段代码:

    String zhangsan, lisi;
    zhangsan = new String("我是对象张三");
    lisi = new String("我是对象李四");
    zhangsan = lisi;
    

    zhangsan = lisi; 执行过后,zhangsan 就不再是"我是对象张三"的引用了;zhangsan 和 lisi 指向了同一个对象(“我是对象李四”);因此,你知道 System.out.println(zhangsan == lisi); 打印的是 false 还是 true 了吗?

    二、堆、栈、堆栈

    谁来告诉我,为什么有很多地方(书、博客等等)把栈叫做堆栈,把堆栈叫做栈?搞得我都头晕目眩了——绕着门柱估计转了 80 圈,不晕才怪!

    我查了一下金山词霸,结果如下:

    我的天呐,更晕了,有没有!怎么才能不晕呢?我这里有几招武功秘籍,你们尽管拿去一睹为快:

    1)以后再看到堆、栈、堆栈三个在一起打牌的时候,直接把“堆栈”踢出去;这仨人不适合在一起玩,因为堆和栈才是老相好;你“堆栈”来这插一脚算怎么回事;这世界上只存在“堆、栈”或者“堆栈”(标点符号很重要哦)。

    2)堆是在程序运行时在内存中申请的空间(可理解为动态的过程);切记,不是在编译时;因此,Java 中的对象就放在这里,这样做的好处就是:

    当需要一个对象时,只需要通过 new 关键字写一行代码即可,当执行这行代码时,会自动在内存的“堆”区分配空间——这样就很灵活。

    另外,需要记住,堆遵循“先进后出”的规则(此处有雷)。就好像,一个和尚去挑了一担水,然后把一担水装缸里面,等到他口渴的时候他再用瓢舀出来喝。请放肆地打开你的脑洞脑补一下这个流程:缸底的水是先进去的,但后出来的。所以,我建议这位和尚在缸上贴个标签——保质期 90 天,过期饮用,后果自负!

    还是记不住,看下图:

    (不好意思,这是鼎,不是缸,将就一下哈)

    3)栈,又名堆栈(简直了,完全不符合程序员的思维啊,我们程序员习惯说一就是一,说二就是二嘛),能够和处理器(CPU,也就是脑子)直接关联,因此访问速度更快;举个十分不恰当的例子哈——眼睛相对嘴巴是离脑子近的一方,因此,你可以一目十行,但绝对做不到一开口就读十行字,哪怕十个字也做不到

    既然访问速度快,要好好利用啊!Java 就把对象的引用放在栈里。为什么呢?因为引用的使用频率高吗?

    不是的,因为 Java 在编译程序时,必须明确的知道存储在栈里的东西的生命周期,否则就没法释放旧的内存来开辟新的内存空间存放引用——空间就那么大,前浪要把后浪拍死在沙滩上啊。

    现在清楚堆、栈和堆栈了吧?

    三、基本数据类型

    先来看《Java 编程思想》中的一段话:

    在程序设计中经常用到一系列类型,他们需要特殊对待。之所以特殊对待,是因为 new 将对象存储于“堆”中,故用 new 创建一个对象──特别小、简单的变量,往往不是很有效。因此,不用new来创建这类变量,而是创建一个并非是引用的变量,这个变量直接存储值,并置于栈中,因此更加高效。

    在 Java 中,这些基本类型有:boolean、char、byte、short、int、long、float、double 和 void;还有与之对应的包装器:Boolean、Character、Byte、Short、Integer、Long、Float、Double 和 Void;它们之间涉及到装箱和拆箱,点击链接。

    看两行简单的代码:

     int a = 3;
     int b = 3;
    

    这两行代码在编译的时候是什么样子呢?

    编译器当然是先处理 int a = 3;,不然还能跳过吗?编译器在处理 int a = 3; 时在栈中创建了一个变量为 a 的内存空间,然后查找有没有字面值为 3 的地址,没找到,就开辟一个存放 3 这个字面值的地址,然后将 a 指向 3 的地址。

    编译器忙完了 int a = 3;,就来接着处理 int b = 3;;在创建完 b 的变量后,由于栈中已经有 3 这个字面值,就将 b 直接指向 3 的地址;就不需要再开辟新的空间了。

    依据上面的概述,我们假设在定义完 a 与 b 的值后,再令 a=4,此时 b 是等于 3 呢,还是 4 呢?

    思考一下,再看答案哈。

    答案揭晓:当编译器遇到 a = 4;时,它会重新搜索栈中是否有 4 的字面值,如果没有,重新开辟地址存放 4 的值;如果已经有了,则直接将 a 指向 4 这个地址;因此 a 值的改变不会影响到 b 的值哦。

    最后,留个作业吧,下面这段代码在运行时会输出什么呢?

    public class Test1 {
        public static void main(String args[]) {
            int a = 1;
            int b = 1;
    
            a = 2;
    
            System.out.println(a);
            System.out.println(b);
    
            TT t = new TT("T");
            TT t1 = t;
            t.setName("TT");
    
    
            System.out.println(t.getName());
            System.out.println(t1.getName());
        }
    }
    
    class TT{
        private String name;
    
        public TT (String name) {
            this.name = name;
        }
    
        public String getName() {
            return this.name;
        }
    
        public void setName(String name1) {
            this.name = name1;
        }
    }
    

    上一篇:如何理解 Java 中的继承?

    下一篇:Java 的操作符——“=”号

    微信搜索「沉默王二」公众号,关注后回复「免费视频」获取 500G Java 高质量教学视频(已分门别类)。

    展开全文
  • 【JavaScript-7】Javascript对象

    千次阅读 多人点赞 2022-04-02 14:57:49
    几乎JavaScript的一切都是对象对象用于数据或者功能集合。到目前为止,我们一直用的是变量来存储数据。但是这种写法并不好~因为这些值是不相关的! let name = '搞前端的半夏'; let age = 18; 不过有了对象,...

    大家好,我是半夏👴,一个刚刚开始写文的沙雕程序员.如果喜欢我的文章,可以关注➕ 点赞 👍 加我微信:frontendpicker,一起学习交流前端,成为更优秀的工程师~关注公众号:搞前端的半夏,了解更多前端知识!点我探索新世界!

    几乎JavaScript中的一切都是对象,对象用于数据或者功能集合。到目前为止,我们一直用的是变量来存储数据。但是这种写法并不好~因为这些值是不相关的!

    let name = '搞前端的半夏';
    let age = 18;
    

    不过有了对象,我们就可以将这两个值组合在一起。

    let person = {
         name : '搞前端的半夏',
         age : 18
    };
    

    在这个例子中,我们将name和age放在Person对象中!

    我们使用typeof来判断person的类型!

    typeof person
    
    

    image-20220328214257337

    我们可以在控制台中展开查看person

    image-20220328214337246

    你会发现,对象的属性和我们放入的顺序不同。这也其实意味着:对象中的顺序无关紧要

    除了变量,对象上面也可以有方法。

    let person = {
         name : '搞前端的半夏',
         age : 18,
        sayHello:function() {
            console.log(this.name)
        }
    };
    

    创建对象

    对象字面量

    通常我们使用闭合的大括号来创建一个对象,这种方式被称为对象字面量语法

    let person = {
    };
    

    new Object

    let person = new Object({
     name : '搞前端的半夏',
         age : 18,
    });
    

    通常我们不用使用这种写法,因为对象字面量语法更清晰。

    事实上,如果你愿意,你可以通过做来创建字符串,const name = new String('wes');但我们不这样做,因为使用字符串文字语法更简单、更短。

    对象的属性在左边,中间是冒号,右边是值。

    对象属性的值尔可以是任何类型(字符串、函数、布尔值、其他对象、数组等)。

    const 陷阱

    在学习JavaScript变量的时候,我们已经了解了const定义的变量的值,无法进行修改,我们当时也学会到,const并不意味着对象的值不能改变。const意味着不能更改对该变量的绑定(引用)。

    还是person,不过我们这里的person是const声明的。

    const person = {
         name : '搞前端的半夏',
         age : 18,
        sayHello:function() {
            console.log(this.name)
        }
    };
    

    我们来修改person的指向,会报错,这也就是我们上面说的无法修改变量的绑定。

    person={}
    

    image-20220328222512127

    但是我们去修改age,是可以成功修改的。

    person.gae=19
    

    image-20220328222611871

    访问属性

    点操作符

    我们想访问age属性的值可以使用**.**操作符来获取。

    person.age
    

    image-20220328222951157

    方括号

    person['age']
    
    

    image-20220328223046052

    删除属性

    要删除属性对象,请使用delete关键字。

    例如delete person.age;将删除age属性。

    image-20220328223227311

    展开全文
  • python创建对象(object)

    万次阅读 多人点赞 2019-06-15 06:54:02
    该系列文章: ...《python创建对象(object)》 在上一篇文章《python的数据类型(list,tuple,dict,set,None)》的1.2小节里我们就简要介绍过对象(object)跟类(class)的概念。也知道了python...

    该系列文章:

    在上一篇文章《python中的数据类型(list,tuple,dict,set,None)》的1.2小节里我们就简要介绍过对象(object)跟类(class)的概念。也知道了python中内置的所有数据类型都是对象,拥有自己的方法。那么当这些内置的数据类型无法满足我们的需求时,我们如何创建我们自己的类型(type)呢?答案就是通过创建我们自己的类(class)。通过我们自己动手实现的类,我们就可以创建以这个类为模板的对象。从这样的流程来看,面向对象的编程方式是自顶而下,首先需要全盘考虑,才能创建一个足够好的模板,也即类。然后才能将类实例化为对象,通过对象中的属性来解决问题或者与其他对象互动。

    创建一个最简单的类可以通过下面这样的写法:

    class User:
        pass
        #更多代码
        #更多代码
    
    复制代码

    上面的代码中class是关键字,表明我们要创建一个类了,User是我们要创建的类的名称。通过“:”和缩进来表明所有缩进的代码将会是这个类里的内容。从User类中创建一个该类的实例通过下面的写法:

    """
    创建一个实例,通过类名加括号的形式,类似调用函数
    """
    u=User()
    
    复制代码

    对象(客体)有自己的特征和自己可以做到的事,对应到程序里就是字段(field)方法(method) ,这两个都是对象的属性(attribute) 。对象的字段类似于普通变量,所不同的是对象的字段是对象独有的。对象的方法类似于普通函数,所不同的是对象的方法是对象独有的。上篇文章中我们已经见到过如何使用字段跟方法,那就是通过.操作符。

    1.0.定义方法(method)

    在类中定义对象的方法(method)比较简单,跟实现普通函数类似,只有一点不同,那就是不管方法需不需要参数,你都需要把self作为一个参数名传进去,self这个参数在我们调用方法时我们可以直接忽略,不赋值给它。举个例子:

    class User:
        def hi(self):
            print("hi!")
    
    u=User()
    u.hi()
    
    """
    程序输出:
    hi!
    """
    
    复制代码

    self这个参数名是约定俗成的。在User类的代码块里定义hi方法时,传入的参数self将会是某个实例(对象)本身。当u作为User类的实例被创建,并且通过u.hi()调用hi方法时,python解释器会自动将其转换成User.hi(u)。通过传入实例(对象)本身,也即self,方法(method)就能够访问实例的字段(filed),并对其进行操作,我们之后可以从新的例子中看到。

    1.1.声明字段(field)

    要在类中声明对象的字段,有一个特殊的方法(method)可以做到,那就是__init__方法,这个方法在init前后都要写上两个下划线____init__方法会在实例一开始创建的时候就被调用,initinitialization的缩写,顾名思义,就是初始化的意思。__init__方法在创建对象的时候由python解释器自动调用,不需要我们手动来调用。看个例子:

    class User:
        """
        注意self总是在括号里的最左边
        """
        def __init__(self,name,age):
            self.name=name
            self.age=age
    
        def hi(self):
            print("hi!I'm {}".format(self.name))
    
    u=User("li",32)
    u.hi()
    print(u.name+","+str(u.age))
    
    """
    程序输出:
    hi!I'm li
    li,32
    """
    
    复制代码

    上面的代码里,在User类的__init__方法中self被传入,那么就可以通过self.nameself.age来声明对象的两个字段,并将传入该方法的参数nameage赋值给它们。当我们创建类型为User的对象的时候,传入实际的参数"li"32,这两个参数被python解释器传入__init__方法中,"li"对应name32对应age__init__方法立即被调用,将实例u的字段一一建立。

    self.name=name粗看貌似都是name变量,但self.name是实例的字段,专属于实例,name是创建对象时将要传入的一个参数,将它赋值给self.name是没有歧义的。

    1.2.实例变量与类变量

    事实上,字段除了独属于实例之外,跟普通变量没有什么差别,所以实例的字段也被称为实例变量。在类的定义中,与实例变量对应的还有类变量,类变量与实例变量类似,通过.操作符来访问。类变量是任何实例共享的,可以理解为是该类型所共有的特征,比如,在User类中,我们可以计算一共有多少被实例化了的用户:

    class User:
        """
        计算被实例化的用户数量
        """
        count=0
    
        def __init__(self,name,age):
            """每次创建一个对象,用户数量在原有基础上加1"""
            User.count=User.count+1
            self.name=name
            self.age=age
    
        def hi(self):
            print("hi!I'm {}".format(self.name))
    
        def die(self):
            print("I'm {}, dying...".format(self.name))
            User.count=User.count-1
            del self
        
        @classmethod
        def print_count(cls):
            print("共有{}名用户".format(cls.count))
    
    
    u=User("li",32)
    User.print_count()
    u.hi()
    
    u1=User("ma",30)
    u1.__class__.print_count()
    u1.hi()
    
    u.die()
    User.print_count()
    u1.die()
    User.print_count()
    
    """
    程序输出:
    共有1名用户
    hi!I'm li
    共有2名用户
    hi!I'm ma
    I'm li, dying...
    共有1名用户
    I'm ma, dying...
    共有0名用户
    """
    
    复制代码

    上面代码中的count就是类变量,可以通过User.count来访问。python通过@classmethod来表明它下面定义的方法是类的方法(method),类的方法中的cls是类本身,跟self使用方法类似,调用类方法时可以直接忽略。类变量跟类的方法(method)都可以被称为类的成员。除了使用类似User.count这样的方式来访问和使用之外,该类的实例还可以通过__class__属性来访问和使用类成员,比如上面代码中的u1.__class__.print_count()

    上面代码中定义的字段跟方法都是公开的,可以通过.操作符访问。但如果属性是以形如__name这样以双下划线为开头的名称,则python会自动将名称换成_classname__name,其中classname就是类的名称,这样,通过an_object.__name是访问不到的。

    1.3.继承(inherit)

    现实世界里,某一类相似客体的类型被抽象为一个概念(名称),同时又有另一类相似客体的类型被抽象为一个概念(名称),这时候我们可能会发现,这两个概念(名称)之间很相似,于是我们把这两个相似概念再抽象成一个概念(名称),这样的过程可以重复多次。举个例子,我们有幼儿园,同时有小学,这时候我们可以把幼儿园跟小学抽象成学校。那跟现实类似,对象的类型跟类型之间,可以抽象成另一个类型。在文章最开头我们说面向对象编程是自顶而下,这跟一层层向上抽象的过程正好相反,我们会在一开始思考如何创建某个类,然后把这个类作为基类(父类) ,更具体的创建一(几)个新类,这一(几)个新类不仅拥有基类的属性,还会增加自己独有的属性。我们把这样的新类(class)叫做子类,是从基类继承而来的。

    从1.2小节的代码例子中,我们创建了一个User(用户)类,假如我们现在需要区分免费用户和付费用户,免费用户跟付费用户都具有nameagehi属性,同时免费用户跟付费用户还具有自己独有的一些属性。如果我们直接分别创建免费用户类跟付费用户类,那么这两个类之间共同的属性就会被定义两次,需要复制粘贴同样的代码,这样的代码质量不高并且不够简洁。相反,我们可以让免费用户跟付费用户都从User类继承下来,这样就可以重用(reuse) User类的代码,并且让代码相对简洁高效一点。还有一个好处就是,当免费用户跟付费用户之间共同的属性有了变化(增减),我们可以直接修改父类User,而不用分别修改,当子类的数量很多时,这种好处会显得非常明显。修改父类之后,各子类的独有属性不会受到影响。

    1.2小节的代码例子中,我们对实例的数量进行统计,当子类从User类继承下来后,在子类实例化对象的时候,父类的实例数量在python中默认也会增多,这说明我们可以把子类的实例看做是父类的实例,这被称为多态性(polymorphism)。免费用户类跟付费用户类如何从父类继承,如下:

    class User:
        """
        计算被实例化的用户数量
        """
        count=0
    
        def __init__(self,name,age):
            """每次创建一个对象,用户数量在原有基础上加1"""
            User.count=User.count+1
            self.name=name
            self.age=age
    
        def hi(self):
            print("hi!I'm {}".format(self.name))
    
        def die(self):
            print("I'm {}, dying...".format(self.name))
            User.count=User.count-1
            del self
        
        @classmethod
        def print_count(cls):
            print("共有{}名用户".format(cls.count))
    
    class  Free_user(User):
        
        def __init__(self,name,age,number_of_ads):
            User.__init__(self,name,age)
            self.number_of_ads=number_of_ads
    
        def hi(self):
            User.hi(self)
            print("I'm free_user")
    
    class  Paying_user(User):
        def __init__(self,name,age,plan):
            User.__init__(self,name,age)
            self.plan=plan
    
        def hi(self):
            print("hi!I'm {},paying_user".format(self.name,))
    
    
    u=Free_user("li",32,5)
    User.print_count()
    u.hi()
    
    u1=Paying_user("ma",30,"5$")
    User.print_count()
    u1.hi()
    
    u.die()
    User.print_count()
    u1.die()
    User.print_count()
    
    
    """
    程序输出:
    共有1名用户
    hi!I'm li
    I'm free_user
    共有2名用户
    hi!I'm ma,paying_user
    I'm li, dying...
    共有1名用户
    I'm ma, dying...
    共有0名用户
    """
    
    复制代码

    上面代码中首先创建了User基类,然后从User类继承下来两个子类:Free_userPaying_user。子类要从某个类继承而来,需要在类名后面跟上括号,在括号中填入基类的名称,形如这样:Free_user(User)

    在子类的__init__方法中,通过调用基类的__init__方法把继承自基类的共有字段创建出来,调用的时候将self跟传入的属于基类部分的参数原样传入,上面代码中将传入的nameage原样传入了基类的__init__方法中了。因为我们在子类中定义了__init__方法,所以python不会自动调用基类的__init__方法,而需要我们显式地调用它。如果子类中没有定义__init__方法,则python会在创建子类的实例时自动调用基类的__init__方法。这是为什么呢?我们在子类中对基类的hi方法进行了重写,但对die方法则没有,但是我们通过子类创建的实例能够调用die方法,这说明在调用die方法时子类的实例被看做了父类的实例了,同时在调用hi方法时却都调用了重写的子类中的方法了,这说明,当实例调用一个方法时,会首先在实例化自己的类中寻找对该方法的定义,如果没有,则在该类的父类中寻找,如果父类中还是没有,则会在父类的父类中寻找,这样的过程一直重复,直到再也没有父类了,如果还是没有该方法,那程序就会报错。

    最后,从前一小节我们知道,以双下划线为前缀的属性名会被python自动替换成另一个名称,这时候当父类中有个以双下划线为前缀的属性,我们在子类中也有一个相同的属性的时候,由于python自动替换了这两个属性名称,子类中的方法并没有覆盖掉父类中的属性,而只是,子类中的该属性跟父类中的该属性是两个不同的属性。看例子:

    #其他一些属性用“,”省略了
    >>> class a:
    ...     def __a_method(self):
    ...         pass
    ... 
    >>> dir(a())
    ['__class__', ,,, '_a__a_method']
    >>> class b(a):
    ...    def __a_method(self):
    ...         pass
    ... 
    >>> dir(b())
    ['__class__', ,,, '_a__a_method', '_b__a_method']
    >>> 
    
    复制代码

    可以看到,__a_methoda类的实例中被替换成了_a__a_method,在b类的实例中被替换成了_b__a_method,这跟_a_a_method不同,b类的实例中继承了_a_a_method,同时,还有自己类型的_b_a_method

    1.4.类(class),对象(object)与类型(type)之间的关系

    看个例子:

    >>> list.__base__
    <class 'object'>
    >>> type(list)
    <class 'type'>
    >>> class User:
    ...     pass
    ... 
    >>> User.__base__
    <class 'object'>
    >>> type(list)
    <class 'type'>
    
    复制代码

    类的属性__base__可以指明该类是继承自哪个类。从上面的例子可以看到,python中定义内置数据类型的类(class)(以list为例)从object类继承而来,但是其类型(type)是type类,我们自己创建并且没有明确指定从是哪个类继承而来的类(以User为例),跟内置类型一样,从object类继承而来,其类型(type)是type类。如果我们自己创建的,并且从层次更低的类(比如User类)中继承而来,那么该类的__base__(基类)跟type函数所显示的类型是怎么样的呢,接上面的例子:

    >>> Free_user.__base__
    <class '__main__.User'>
    >>> type(Free_user)
    <class 'type'>
    >>> 
    
    复制代码

    可以看到,Free_userUser继承而来,但其类型依然是type,所以所有的类(class)的类型应当都是type,是不是这样呢,object会不会例外呢?type自己呢?它的类型呢?下面的例子验证了它们的类型也是type

    >>> type(object)
    <class 'type'>
    >>> type(type)
    <class 'type'>
    
    复制代码

    从例子中我们知道了,所有的类(class)的类型都是type类,所以,所有的类(class)都是从type类中实例化出来的实例,甚至type类实例化了自己,所以所有的类包括objecttype都是实例,这说明所有的类都是对象 。为了清晰的指代不同种类的对象,我们把本身是类的对象称为类对象,把从类中实例化而来并且本身不是类的对象成为实例对象,实例对象是层次最低的对象。

    我们可以看到object类跟type类是python中抽象层次最高的对象了。那么它们两个的关系如何呢?看例子:

    >>> type.__base__
    <class 'object'>
    >>> print(object.__base__)
    None
    >>> 
    
    复制代码

    可以看到,typeobject继承而来,并且我们已经知道object的类型是type。从例子中可以看到object没有基类,所以如果把类的层层继承想象成一条锁链,那么object将是继承链上的顶点。前面我们提到的对象的一些特殊属性如__init____class__继承自object,而__base__这个特殊属性则只有类对象才有,是在type中定义的。如下:

    #其他一些属性用“,”省略了
    >>> dir(object)
    ['__class__', ,,, '__init__', ,,, '__subclasshook__']
    >>> dir(type)
    ['__abstractmethods__', '__base__', '__bases__', ,,, 'mro']
    >>> 
    
    复制代码

    欢迎浏览我的个人博客,https://diwugebingren.github.io

    转载于:https://juejin.im/post/5d0495b3e51d4510617210bb

    展开全文
  • 深入理解Python的面向对象

    万次阅读 多人点赞 2017-06-12 06:42:41
    面向过程与面向对象的对比 id、type和value的讲解 类和对象的概念 初始化构造函数__init__的作用 self关键字的使用 继承的概念 组合的概念 接口的概念 抽象类的概念 1、面向过程与面向对象的对比面向过程的程序设计...
  • 对C++面向对象的编程的理解

    千次阅读 2019-01-16 18:05:06
    面向对象方法历经了30多年的研究和发展,已经日益成熟和完善,应用也越来越深入和广泛,现其已经发展为主流的软件开发方法。 本节主要介绍面向对象方法的优点以及它的一些基本概念。 2.3.1面向对象方法的优点(1)与...
  • 面向对象软件,也有很多共享相同特征的不同的对象,可以利用这些对象的相同特征为它们建立一个集合,而这个集合就称为类。 C++ 类是把各种不同类型的数据(称为数据成员)和对数据的操作(成员函数)组织...
  • Java面向对象详解

    万次阅读 2022-03-07 11:33:08
    1、初识面向对象: 面向过程vs面向对象 面向过程思想:步骤清晰简单,第一步做什么,第二步做什么……,面向过程适合处理一些较为简单的问题 面向对象思想:物以类聚,分类的思维模式,思考问题首先会解决问题...
  • 一、面向对象程序设计(OOP)的三大基本特征(定义、特性、优缺点、java的表现形式、应用) 1.封装 封装的定义 ​ 通俗的说:普通人对计算机进行应用操作,只需知道如何计算机上连网,如何浏览网页,下载东西...
  • 阿里面试失败后,一气之下我图解了Java18把锁

    万次阅读 多人点赞 2021-06-17 23:21:47
    目录 乐观锁和悲观锁 独占锁和共享锁 互斥锁和读写锁 公平锁和非公平锁 ...悲观锁对应于生活悲观的人,悲观的人总是想着...回到代码世界中,一个共享数据加了悲观锁,那线程每次想操作这个数据前都会假设其他线程.
  • 如电影所讲,现实也有着类似的情节,我们的生活,我们所看过的图片、视频和游览过的网页,也许就隐藏着他人需要传输的秘密信息(是不是有点恐怖,差一点成为帮凶了),这就是信息隐藏!由于应用场景一般比较...
  • Java类和对象的关系

    千次阅读 2020-07-29 22:14:58
    2、对象对象表示现实世界中一个具体的事物。对象是类的一个实例,有状态和行为。例如,一条狗是一个对象,它的状态有:颜色、名字、品种;行为有:摇尾巴、叫、吃等。(比如根据汽车设计图纸设计出来的汽车) 3、...
  • 万字长文深度剖析面向对象的javascript

    万次阅读 热门讨论 2020-12-02 09:46:56
    本将会深入讲解面向对象在javascript的应用,并详细介绍三种对象的生成方式:构造函数,原型链,类。
  • 计算机中信息的表示

    千次阅读 2021-07-27 03:54:06
    计算机中信息的表示1.3.1 数制1、数制的基本概念及常用数制什么是数制?简单地说,数制就是用一组固定的数码和一套统一的规则来表示数值的方法。一种数制中所使用的数码的个数称为该数制的基数。既然有不同的数制...
  • java什么是面向对象

    千次阅读 2021-02-12 11:15:58
    java面向对象是指计算机程序,模拟现实世界中的概念,借助对象的描述计算机程序中用类似的实体模拟现实世界中的实体。什么是对象和面向对象的编程?对象就是存在的具体实体,具有明确定义的状态和行为,是面向...
  • java什么是类?什么是对象

    万次阅读 多人点赞 2018-06-03 19:29:55
    首先什么是对象呢?可谓是万物皆对象对象是客观存在的...计算机的世界里面,计算机关注的事数据信息,我们描述数据信息的时候一定要要描述数据类型,对象就是具体的数据信息,类是信息的数据类型。对象的属性...
  • JavaScript 对象解构用法解析

    千次阅读 多人点赞 2022-02-16 10:47:21
    点我探索新世界! 扫码或搜索添加文末公众号「搞前端的半夏」: ???? 硬核资料:领取1000+PPT模板、100+简历模板、行业经典书籍PDF。 ???? 回复 ”网站模板“,免费送网站模板! ???? 回复 ”面试“:免费送你前端...
  • C++面向对象程序设计 面向对象编程

    万次阅读 多人点赞 2018-09-12 22:39:50
    1.1 面向过程的编程风格与面向对象的编程风格 C语言是面向过程语言,也称为命令型语言,面向过程通常采用自顶向下设计,问题复杂时不断运用自顶向下设计(即函数分解法)直到容易处理。自顶向下设计优点是直观有...
  • JavaClass对象详解

    万次阅读 多人点赞 2018-06-01 14:50:40
    https://blog.csdn.net/mcryeasy/article/details/52344729待优化整理 总结Class类简介  java世界里,一切皆对象。从某种意义上来说,java有两种对象:实例对象和Class对象。每个类的运行时的类型信息就是用...
  • Java完全支持使用对象、类、继承、封装、消息等基本概念来进行程序设计,允许从现实世界中客观存在的事物(即对象)出发来构造软件系统,系统构造尽可能运用人类的自然思维方式。 1,结构化程序设计 ...
  • 如何理解Java的面向对象

    万次阅读 多人点赞 2018-08-01 14:28:30
    &nbsp;&nbsp;...我的理解是:面向对象是向现实世界模型的自然延伸,这是一种”万物皆对象”的编程思想。现实生活的任何物体都可以归为一类事物,而每一个个体都是一类事物的实例。 &
  • java面向对象简介

    千次阅读 多人点赞 2021-11-06 13:59:14
    因此,尽管人们发现C++不太适用,但设计Java的时候还是尽可能地接近C++,以便系统更易于理解,Java剔除了C++许多很少使用、难以理解、易混淆的特性。目前看来,这些特性带来的麻烦远远多于其带来的好处。 的确...
  • 第一题:面向对象设计应该遵循哪些准则?...• 把数据结构和操作这些数据的方法紧密地结合一起 (2)抽象 • 过程抽象 • 数据抽象:类 • 参数化抽象:C++的“模板” (3)信息隐藏 • 通过...
  • java什么是类什么是对象

    千次阅读 2019-04-04 10:40:14
    Java是一种面向对象的程序设计语言(Object Oriented Programming:OOP),面向对象的程序设计语言有类和对象的概念,那么它们概念上到底有什么区别呢? 下面以java语言为例解释下什么是类,什么是对象? 类...
  • 面向对象基本概念

    万次阅读 多人点赞 2019-02-06 21:56:15
    面向对象就是:把数据及对数据的操作方法放在...程序流程由用户使用决定。对象即为人对各种具体物体抽象后的一个概念,人们每天都要接触各种各样的对象,如手机就是一个对象。 面向对象编程(OOP:object-orie...
  • Java面向对象的理解

    千次阅读 多人点赞 2019-03-17 00:03:55
    从现实世界中客观存在的事物(即对象)出发来构造软件系统,并且系统构造尽可能运用人类的自然思维方式。所谓对象就是真实世界中的实体,对象与实体是一一对应的,也就是说现实世界中每一个实体都是一个对象,它...
  • 怎样理解对象

    千次阅读 2018-08-01 11:28:59
    它只是我们从现实世界中抽象出来的一种模型,但是这个模型还是有它的定义和概念的。   1、对象的英文单词是“Object”,它有三个方面的意思: (1)目标,目的,宗旨 (2)物,物体,物件 (3)对象,客体,客观 ...
  • 因为想笔记夹杂这篇文章部分内容,所以进行了还是比较多的引用,核心的地方还是自己写的 可以一直接调转到深入理解Java的OOP 大纲 一、OOA 名称:Object-Oriented Analysis:面向对象分析方法 OOA是指...
  • 面向对象程序设计概念

    千次阅读 2019-09-26 17:03:28
    一. 程序设计范型   面向对象程序设计(object-oriented programming,OOP)是一种新的程序设计的范型。程序设计范型是设计程序的规范、模型和风格,它是一类程序设计语言的...二、程序的一切操作都是向对象发...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 164,042
精华内容 65,616
热门标签
关键字:

对象在信息世界中称为