• 关于

    类和对象继承

    的搜索结果

回答

封装(Encapsulation) 所谓封装,也就是把客观事物封装成抽象的类,并且类可以把自己的数据和方法只让可信的类或者对象操作,对不可信的进行信息隐藏。封装是面向对象的特征之一,是对象和类概念的主要特性。简单的说,一个类就是一个封装了数据以及操作这些数据的代码的逻辑实体。在一个对象内部,某些代码或某些数据可以是私有的,不能被外界访问。通过这种方式,对象对内部数据提供了不同级别的保护,以防止程序中无关的部分意外的改变或错误的使用了对象的私有部分。 继承(Inheritance) 继承是指这样一种能力:它可以使用现有类的所有功能,并在无需重新编写原来的类的情况下对这些功能进行扩展。通过继承创建的新类称为“子类”或“派生类”,被继承的类称为“基类”、“父类”或“超类”。继承的过程,就是从一般到特殊的过程。要实现继承,可以通过“继承”(Inheritance)和“组合”(Composition)来实现。继承概念的实现方式有二类:实现继承与接口继承。实现继承是指直接使用基类的属性和方法而无需额外编码的能力;接口继承是指仅使用属性和方法的名称、但是子类必须提供实现的能力; 多态(Polymorphism) 所谓多态就是指一个类实例的相同方法在不同情形有不同表现形式。多态机制使具有不同内部结构的对象可以共享相同的外部接口。这意味着,虽然针对不同对象的具体操作不同,但通过一个公共的类,它们(那些操作)可以通过相同的方式予以调用。 最常见的多态就是将子类传入父类参数中,运行时调用父类方法时通过传入的子类决定具体的内部结构或行为。

montos 2020-06-01 15:44:57 0 浏览量 回答数 0

回答

java上转型对象属性:上转型对象不能操作子类新增加的成员变量,不能使用子类新增的方法。即为较子类B失去一些属性和功能,这些属性和功能是新增的。上转型对象可以操作子类继承或隐藏的成员变量,也可以使用子类继承的或重写的方法。即为上转型对象可以操纵父类原有的属性和功能,无论这些方法是否被重写。上转型对象调用方法时,就是调用子类继承和重写过的方法。而不会是新增的方法,也不是父类原有的方法。可以将对象的上转型对象再强制转换到一个子类对象,强制转换过的对象具有子类所有属性和功能。因为你父类中f()是私有的,没有被子类所继承和重写,所以调用的是自身的f()方法。输出Private f()

蛮大人123 2019-12-02 01:52:10 0 浏览量 回答数 0

回答

面向对象的特征主要有以下几个方面: 抽象:抽象是将一类对象的共同特征总结出来构造类的过程,包括数据抽象和行为抽象两方面。抽象只关注对象有哪些属性和行为,并不关注这些行为的细节是什么。 封装 封装把一个对象的属性私有化,同时提供一些可以被外界访问的属性的方法,如果属性不想被外界访问,我们大可不必提供方法给外界访问。但是如果一个类没有提供给外界访问的方法,那么这个类也没有什么意义了。 继承 继承是使用已存在的类的定义作为基础建立新类的技术,新类的定义可以增加新的数据或新的功能,也可以用父类的功能,但不能选择性地继承父类。通过使用继承我们能够非常方便地复用以前的代码。 关于继承如下 3 点请记住: 子类拥有父类非 private 的属性和方法。 子类可以拥有自己属性和方法,即子类可以对父类进行扩展。 子类可以用自己的方式实现父类的方法。(以后介绍)。 多态 所谓多态就是指程序中定义的引用变量所指向的具体类型和通过该引用变量发出的方法调用在编程时并不确定,而是在程序运行期间才确定,即一个引用变量到底会指向哪个类的实例对象,该引用变量发出的方法调用到底是哪个类中实现的方法,必须在由程序运行期间才能决定。 在Java中有两种形式可以实现多态:继承(多个子类对同一方法的重写)和接口(实现接口并覆盖接口中同一方法)。 其中Java 面向对象编程三大特性:封装 继承 多态 封装:隐藏对象的属性和实现细节,仅对外提供公共访问方式,将变化隔离,便于使用,提高复用性和安全性。 继承:继承是使用已存在的类的定义作为基础建立新类的技术,新类的定义可以增加新的数据或新的功能,也可以用父类的功能,但不能选择性地继承父类。通过使用继承可以提高代码复用性。继承是多态的前提。 关于继承如下 3 点请记住: 子类拥有父类非 private 的属性和方法。 子类可以拥有自己属性和方法,即子类可以对父类进行扩展。 子类可以用自己的方式实现父类的方法。 多态性:父类或接口定义的引用变量可以指向子类或具体实现类的实例对象。提高了程序的拓展性。 在Java中有两种形式可以实现多态:继承(多个子类对同一方法的重写)和接口(实现接口并覆盖接口中同一方法)。 方法重载(overload)实现的是编译时的多态性(也称为前绑定),而方法重写(override)实现的是运行时的多态性(也称为后绑定)。 一个引用变量到底会指向哪个类的实例对象,该引用变量发出的方法调用到底是哪个类中实现的方法,必须在由程序运行期间才能决定。运行时的多态是面向对象最精髓的东西,要实现多态需要做两件事: 方法重写(子类继承父类并重写父类中已有的或抽象的方法); 对象造型(用父类型引用子类型对象,这样同样的引用调用同样的方法就会根据子类对象的不同而表现出不同的行为)。

问问小秘 2020-03-27 17:36:33 0 浏览量 回答数 0

阿里云试用中心,为您提供0门槛上云实践机会!

0元试用32+款产品,最高免费12个月!拨打95187-1,咨询专业上云建议!

回答

Java是一个面向对象的语言。每一个学习过Java的人都知道,封装、继承、多态是面向对象的三个特征。每个人在刚刚学习继承的时候都会或多或少的有这样一个印象:继承可以帮助我实现类的复用。所以,很多开发人员在需要复用一些代码的时候会很自然的使用类的继承的方式,因为书上就是这么写的(老师就是这么教的)。但是,其实这样做是不对的。长期大量的使用继承会给代码带来很高的维护成本。 本文将介绍组合和继承的概念及区别,并从多方面分析在写代码时如何进行选择。 面向对象的复用技术 前面提到复用,这里就简单介绍一下面向对象的复用技术。 复用性是面向对象技术带来的很棒的潜在好处之一。如果运用的好的话可以帮助我们节省很多开发时间,提升开发效率。但是,如果被滥用那么就可能产生很多难以维护的代码。 作为一门面向对象开发的语言,代码复用是Java引人注意的功能之一。Java代码的复用有继承,组合以及代理三种具体的表现形式。本文将重点介绍继承复用和组合复用。 继承 继承(Inheritance)是一种联结类与类的层次模型。指的是一个类(称为子类、子接口)继承另外的一个类(称为父类、父接口)的功能,并可以增加它自己的新功能的能力,继承是类与类或者接口与接口之间最常见的关系;继承是一种is-a关系。(图片来自网络,侵删。) 组合 组合(Composition)体现的是整体与部分、拥有的关系,即has-a的关系。 组合与继承的区别和联系 在继承结构中,父类的内部细节对于子类是可见的。所以我们通常也可以说通过继承的代码复用是一种白盒式代码复用。(如果基类的实现发生改变,那么派生类的实现也将随之改变。这样就导致了子类行为的不可预知性;) 组合是通过对现有的对象进行拼装(组合)产生新的、更复杂的功能。因为在对象之间,各自的内部细节是不可见的,所以我们也说这种方式的代码复用是黑盒式代码复用。(因为组合中一般都定义一个类型,所以在编译期根本不知道具体会调用哪个实现类的方法) 继承,在写代码的时候就要指名具体继承哪个类,所以,在编译期就确定了关系。(从基类继承来的实现是无法在运行期动态改变的,因此降低了应用的灵活性。) 组合,在写代码的时候可以采用面向接口编程。所以,类的组合关系一般在运行期确定。 优缺点对比 组 合 关 系继 承 关 系优点:不破坏封装,整体类与局部类之间松耦合,彼此相对独立缺点:破坏封装,子类与父类之间紧密耦合,子类依赖于父类的实现,子类缺乏独立性优点:具有较好的可扩展性缺点:支持扩展,但是往往以增加系统结构的复杂度为代价优点:支持动态组合。在运行时,整体对象可以选择不同类型的局部对象缺点:不支持动态继承。在运行时,子类无法选择不同的父类优点:整体类可以对局部类进行包装,封装局部类的接口,提供新的接口缺点:子类不能改变父类的接口缺点:整体类不能自动获得和局部类同样的接口优点:子类能自动继承父类的接口缺点:创建整体类的对象时,需要创建所有局部类的对象优点:创建子类的对象时,无须创建父类的对象 如何选择 相信很多人都知道面向对象中有一个比较重要的原则『多用组合、少用继承』或者说『组合优于继承』。从前面的介绍已经优缺点对比中也可以看出,组合确实比继承更加灵活,也更有助于代码维护。 所以, 建议在同样可行的情况下,优先使用组合而不是继承。 因为组合更安全,更简单,更灵活,更高效。 注意,并不是说继承就一点用都没有了,前面说的是【在同样可行的情况下】。有一些场景还是需要使用继承的,或者是更适合使用继承。 继承要慎用,其使用场合仅限于你确信使用该技术有效的情况。一个判断方法是,问一问自己是否需要从新类向基类进行向上转型。如果是必须的,则继承是必要的。反之则应该好好考虑是否需要继承。《Java编程思想》 只有当子类真正是超类的子类型时,才适合用继承。换句话说,对于两个类A和B,只有当两者之间确实存在is-a关系的时候,类B才应该继承类A。《Effective Java》

montos 2020-06-01 15:51:13 0 浏览量 回答数 0

回答

Java实现多态有三个必要条件:继承、重写、向上转型。 继承:在多态中必须存在有继承关系的子类和父类。 重写:子类对父类中某些方法进行重新定义,在调用这些方法时就会调用子类的方法。 向上转型:在多态中需要将子类的引用赋给父类对象,只有这样该引用才能够具备技能调用父类的方法和子类的方法。 只有满足了上述三个条件,我们才能够在同一个继承结构中使用统一的逻辑实现代码处理不同的对象,从而达到执行不同的行为。 对于Java而言,它多态的实现机制遵循一个原则:当超类对象引用变量引用子类对象时,被引用对象的类型而不是引用变量的类型决定了调用谁的成员方法,但是这个被调用的方法必须是在超类中定义过的,也就是说被子类覆盖的方法。

问问小秘 2020-03-27 17:38:37 0 浏览量 回答数 0

回答

Java也支持面向对象的三大特征:封装、继承和多态,Java提供了private、protected和public三个访问控制修饰符来实现良好的封装,提供了extends关键字来让子类继承父类,子类继承父类就可以继承到父类的Field和方法,如果访问控制允许,子类实例可以直接调用父类里定义的方法。继承是实现类复用的重要手段,除此之外,也可通过组合关系来实现这种复用,从某种程度上来看,继承和组合具有相同的功能。使用继承关系来实现复用时,子类对象可以直接赋给父类变量,这个变量具有多态性,编程更加灵活;而利用组合关系来实现复用时,则不具备这种灵活性。

星尘linger 2020-04-07 12:03:07 0 浏览量 回答数 0

回答

假设有个名为Dog的类 1.当首次创建型为Dog的对象时(构造器可以看成静态方法),或者Dog类的静态方法/静态域首次被访问时,Java解释器必须查找类路径,以定位Dog.class文件。 2.然后载入Dog.class(这将创建一个Class对象),有关静态初始化的动作都会执行。因此,静态初始化只在Class对象首次加载的时候进行一次。 3.当你用new Dog()创建对象的时候,首先将在堆上为Dog对象分配足够的存储空间。 4.这块存储空间会被清零,这就自动地将Dog中的所有基本类型数据设置成了默认值(对数字来说就是0,对布尔型和字符型也相同),而引用则被置成了null。 5.执行所有出现于域定义处的初始化动作。 6.执行构造器。这是没有涉及继承的情况,对于涉及了继承的情况总结如下:假设有个名为Mouse4j的类,继承自Mouse,Mouse又继承自Animal1.当首次创建型为Mouse4j的对象时,Java解释器查找类路径,定位Mouse4j.class文件。 2.Java解释器会根据Mouse4j.class定位其基类Mouse.class、再根据Mouse.class定位到基类Animal.class文件,有关静态初始化的动作从基类到子类依次执行。 3.当你用new Mouse4j()创建对象的时候,首先将在堆上为Mouse4j对象(包括其基类Mouse和Animal中的域)分配足够的存储空间。 4.这块存储空间会被清零,这就自动地将Mouse4j中的所有基本类型数据(包括其基类Mouse和Animal中的)设置成了默认值(对数字来说就是0,对布尔型和字符型也相同),而引用(包括其基类Mouse和Animal中的)则被置成了null。 5.执行基类Animal中所有出现于域定义处的初始化动作。 6.执行基类Animal构造器。 7.执行基类Mouse中所有出现于域定义处的初始化动作。 8.执行基类Mouse构造器。 9.执行子类Mouse4j中所有出现于域定义处的初始化动作。 10.执行子类Mouse4j构造器。即:class是从子类到基类依次查找,有关静态初始化的动作从基类到子类依次执行。在为所创建对象的存储空间清零后,找到继承链中最上层的基类,执行a、b两步: a.执行其出现在域定义处的初始化动作 b.然后再执行其构造器 然后从基类到子类依次执行这两步操作。

蛮大人123 2019-12-02 02:21:55 0 浏览量 回答数 0

回答

常用的bai类主要是Object类、String类,util包。 解释 :du Object对象类作为所有对象的底层,也就是说任何的对象都是继承自这个类。 String类是字符串,任何的字符串都是继承自这个类。 util包下面的类,可以实现所有的基本算法和java底层运算。

游客bnlxddh3fwntw 2020-07-02 15:59:35 0 浏览量 回答数 0

回答

<p>你自己也说了,类X没有直接实现接口A和B,但是类X实现的接口D已经继承了接口A和B。</p> A a = x; 这一行,并没有发生实例化。实例化的含义是创建对象,这一行并没有创建对象。这一行实际做的是,让引用a指向引用x所指向的对象。对象并没有增加。 因为类X实现了接口D,而接口D已经继承了接口A和B,所以这一行不会报错。 <ol> 任意一个类 M  成功实现了某个接口 N1 或 N2,就可以将 接口 N1,或 接口N2  当成 类 M 的父类看待。进而,子类 M 的对象 m,自然也就是 N1 或 N2 类型的 实例 (或 引用 referene)。这叫向上转型 upcasting。比如,父类 Person 的子类 Student 的对象是 李明, 李明既是学生 Student 类型 (的引用),也是 人 Person 类型 (的引用)。 在 楼主的案例 里,类 C 要同时实现 接口 A 和 B,但 它不但未能完成要求定义的抽象方法的方法体,而且自身又添加了一个抽象方法。因此,类 C 要冠以 关键词 abstract。 在 楼主的案例 里,接口 D 同时继承 接口 A 和 B。 最后,在 楼主的案例 里,类 X 不但成功继承了 类 C, 同时还 实现了接口 D,也就是同时实现了接口 A 和 B。 这样一来,在 楼主的案例 里,类 X 就可以看作是 接口 A、B、类 C、以及 D 的子类 (subclass/derived_class),类 X 的对象/实体,自然也就可以当做是  接口 A、B、类 C、以及 D 的类型的引用:a、b、c、d ( 这种转变成为 向上转型 upcasting )。用这些引用,自然可以调用相关的方法。     总之,就楼主的案例而言,虽然 类 class X 没有直接实现接口 interface A 和 interface B ,但是它成功继承了 实现 接口 interface A 和 interface B  的抽象类 abstract C。由此,类 class X 便是其父类 C,以及其父接口   interface A 和 interface B  的子类。于是,类 class X 的 实体/对象 x, 就可以向上转型为 其父类、父接口类型的引用, 即楼主所说的 "为父接口实例化"。      参考: 在java 中,什么叫向上转型

爱吃鱼的程序员 2020-06-06 09:57:41 0 浏览量 回答数 0

回答

    1) Servlet接口:提供最基本的管理Servlet生命周期的功能,主要有init(构造)、service(执行服务)、destroy(析构)三大功能,因此Servlet接口是任何Servlet类的生命和希望;    2) ServletConfig接口:提供最基本的查询Servlet配置信息的功能,主要有getServletName(获取当前Servlet注册名)、getInitParameter(获取Servlet初始参数)、getServletContext(获取Servlet环境句柄)等,但是它只是一个接口,因此里面没有ServletConfig对象,只是规定了该接口必须实现的功能;    3) GnericServlet类:它是个真正的类,它实现了Servlet和ServletConfig接口,并且它是所有具体Servlet的框架类,所有Servlet类都是该类的子类(都继承自它),包括HttpServlet类,并且它包含真正的数据对象ServletConfig,可以通过ServletConfig接口中的各种方法获取该对象中的信息(即Servlet配置信息);启动一个Servlet程序的步骤:整个过程都是由Web容器控制的,实际中不实现Servlet类的构造器(构造器是空的),生命周期完全用init、service和destroy控制    1) 首先Web容器会读取web.xml配置信息并创建一个ServletConfig对象,将配置信息存在该对象中;    2) 接着Web容器调用Servlet类的空的构造函数构造一个空的Servlet类对象(里面什么都没有初始化)将其实例化;    3) 然后才是初始化,调用Servlet接口的init(config: ServletConfig)方法,将前面保存Servlet配置的ServletConfig对象作为参数传入init进行初始化,init中只有两句话:public void init(ServletConfig config) throws ServletException { this.config = config; this.init();}         i. 第一句当然是初始化config对象;         ii. 第二句不是调用基类的init函数,因为当前方法本身就是从Servlet接口继承来的方法,第二个无参的init方法是GenericServlet自己定义的方法,专门用来初始化自定义的数据成员(比如自己继承HttpServlet类实现了一个MyServlet类,里面自定义了一个数据成员String myName,而这样的数据成员的初始化就可以放在GenericServlet定义的无参init方法中;    4) 接受请求创建request和response对象并传入service进行服务;    5) 最后在一定条件下(关闭服务器、或主动关闭Servlet)调用destroy方法关闭并回收Servlet的空间;

hiekay 2019-12-02 01:43:15 0 浏览量 回答数 0

回答

由于Java不支持多继承,而有可能某个类或对象要使用分别在几个类或对象里面的方法或属性,现有的单继承机制就不能满足要求。与继承相比,接口有更高的灵活性,因为接口中没有任何实现代码。当一个类实现了接口以后,该类要实现接口里面所有的方法和属性,并且接口里面的属性在默认状态下面都是public static,所有方法默认情况下是public.一个类可以实现多个接口。

YDYK 2020-04-26 16:19:30 0 浏览量 回答数 0

问题

CGLIB无法拦截静态方法问题

蛮大人123 2019-12-01 20:02:33 2445 浏览量 回答数 2

回答

接口是JAVA为了实现类似C++里面的多继承的一种妥协方案。比如,有接口A,然后B、C、D都实现了接口A。就类似于B、C、D都继承了抽象类A,都可以调用A中定义过的方法。比如需要对B、C、D的对象做类似的操作,就可以写出类似的代码。甚至可以把类似的代码抽象封装成函数,类等等。传递参数的时候,可以把类型写成A,那么B、C、D类的对象就都可以传递进来。各种。总之,接口不是为了规范产生的,它的好处也不是什么规范,而是尽量抽象,减少重复的代码。(说的装逼一点,叫更加符合面向对象的思想blabla……)(另外,不规范都是程序员的问题,接口并不能拯救世界。)实现类似的效果,只有两种方案:方案1:B、C、D都继承于A。方案2:B、C、D都实现A的接口。但是很明显,JAVA不支持多继承……于是只能用方案2,实现多个接口……所以你懂的,接口是很必要的。但是用了函数和类,可以为你减少重复的代码啊。你在考虑用继承或者接口的前提,一定是要“ B,C,D具有相同或者类似的行为,可以整合到一起 ”。接口可以让你的B、C、D类的对象都可以当做同一个类型(A接口)的参数到处传递,做相同的操作。(也就是说,比如B继承Y,又实现了Z,那么B既可以当做Y类型的参数,又可以当做Z类型的参数)

蛮大人123 2019-12-02 01:51:10 0 浏览量 回答数 0

问题

JS对象与类的名词性问题

小旋风柴进 2019-12-01 20:24:48 790 浏览量 回答数 1

回答

我了解的 js 中实现继承的几种方式有: (1)第一种是以原型链的方式来实现继承,但是这种实现方式存在的缺点是,在包含有引用类型的数据时,会被所有的实例对象所共享,容易造成修改的混乱。还有就是在创建子类型的时候不能向超类型传递参数。 (2)第二种方式是使用借用构造函数的方式,这种方式是通过在子类型的函数中调用超类型的构造函数来实现的,这一种方法解决了不能向超类型传递参数的缺点,但是它存在的一个问题就是无法实现函数方法的复用,并且超类型原型定义的方法子类型也没有办法访问到。 (3)第三种方式是组合继承,组合继承是将原型链和借用构造函数组合起来使用的一种方式。通过借用构造函数的方式来实现类型的属性的继承,通过将子类型的原型设置为超类型的实例来实现方法的继承。这种方式解决了上面的两种模式单独使用时的问题,但是由于我们是以超类型的实例来作为子类型的原型,所以调用了两次超类的构造函数,造成了子类型的原型中多了很多不必要的属性。 (4)第四种方式是原型式继承,原型式继承的主要思路就是基于已有的对象来创建新的对象,实现的原理是,向函数中传入一个对象,然后返回一个以这个对象为原型的对象。这种继承的思路主要不是为了实现创造一种新的类型,只是对某个对象实现一种简单继承,ES5 中定义的 Object.create() 方法就是原型式继承的实现。缺点与原型链方式相同。 (5)第五种方式是寄生式继承,寄生式继承的思路是创建一个用于封装继承过程的函数,通过传入一个对象,然后复制一个对象的副本,然后对象进行扩展,最后返回这个对象。这个扩展的过程就可以理解是一种继承。这种继承的优点就是对一个简单对象实现继承,如果这个对象不是我们的自定义类型时。缺点是没有办法实现函数的复用。 (6)第六种方式是寄生式组合继承,组合继承的缺点就是使用超类型的实例做为子类型的原型,导致添加了不必要的原型属性。寄生式组合继承的方式是使用超类型的原型的副本来作为子类型的原型,这样就避免了创建不必要的属性。

剑曼红尘 2020-04-03 15:14:53 0 浏览量 回答数 0

回答

继承是类和类之间才有的关系,写法上是 { //类定义 } 这种形式。意思是MyClassName继承自BaseClassName。你写的那句话的意思是**定义一个MultiCopter类的对象**,名字是aparm。由于MultiCopter类是嵌套类,因此要在前面加上外层类的类名和"::"作用域选择符。

a123456678 2019-12-02 01:58:07 0 浏览量 回答数 0

回答

"通过继承Thread类或实现Runnable、Callable接口都可以实现多线程,不过实现Runnable接口与实现Callable接口的方式基本相同,只是Callable接口里定义的方法有返回值,可以声明抛出异常而已。因此可以将实现Runnable接口和实现Callable接口归为一种方式。这种方式与继承Thread方式之间的主要差别如下。采用实现Runnable、Callable接口的方式创建多线程—— 线程类只是实现了Runnable接口或Callable接口,还可以继承其他类。 在这种方式下,多个线程可以共享同一个 target 对象,所以非常适合多个相同线程来处理同一份资源的情况,从而可以将CPU、代码和数据分开,形成清晰的模型,较好地体现了面向对象的思想。 劣势是:编程稍稍复杂,如果需要访问当前线程,则必须使用Thread.currentThread()方法。采用继承Thread类的方式创建多线程—— 劣势是:因为线程类已经继承了Thread类,所以不能再继承其他父类。 优势是:编写简单,如果需要访问当前线程,则无须使用 Thread.currentThread()方法,直接使用this即可获得当前线程。鉴于上面分析,因此一般推荐采用实现Runnable接口、Callable接口的方式来创建多线程。"

星尘linger 2020-04-12 11:49:59 0 浏览量 回答数 0

回答

为了降低复杂性并简化语言,java不支持多重继承。考虑一个场景,其中A,B和C是三个类别。 C类继承A和B类。如果A和B类具有相同的方法,并且您从子类对象调用它,则将有歧义来调用A或B类的方法。 由于编译时错误比运行时错误要好,因此如果您继承2个类,则Java会呈现编译时错误。因此,无论您使用的是相同的方法还是不同的方法,都会出现编译时错误。

YDYK 2020-04-23 23:03:11 0 浏览量 回答数 0

问题

java普通类中能否获取request对象

蛮大人123 2019-12-01 19:31:31 1212 浏览量 回答数 1

回答

简单来说,类是一种高级抽象,就是一种高级的数据类型,是对象的蓝图,就是用来定义你要用的对象的属性和行为的,为什么要使用类,你可以和之前没有类的时候进行比较,比如和结构化编程比较,有了类有什么好处,总结就是封装、继承、多态

半指温柔乐 2019-12-02 01:09:39 0 浏览量 回答数 0

回答

简单来说,类是一种高级抽象,就是一种高级的数据类型,是对象的蓝图,就是用来定义你要用的对象的属性和行为的,为什么要使用类,你可以和之前没有类的时候进行比较,比如和结构化编程比较,有了类有什么好处,总结就是封装、继承、多态

半指温柔乐 2019-12-02 01:09:24 0 浏览量 回答数 0

回答

简单来说,类是一种高级抽象,就是一种高级的数据类型,是对象的蓝图,就是用来定义你要用的对象的属性和行为的,为什么要使用类,你可以和之前没有类的时候进行比较,比如和结构化编程比较,有了类有什么好处,总结就是封装、继承、多态

半指温柔乐 2019-12-02 01:09:30 0 浏览量 回答数 0

问题

Hibernate中,继承映射还是使用"type"字段区分

云栖技术 2019-12-01 19:40:15 957 浏览量 回答数 1

回答

构造方法与其他普通方法不同的地方在于,当一个对象被创建后,会立即调用构造方法。在python中创建一个构造方法很简单,只需要把init方法的名字从简单的init修改为魔法版本__init__即可。class foobar:  def __init__(self):    self.somevar = 42f = foobar()f.somevar42如果给构造方法传递几个参数的话,会怎么样呢?class foobar:... def __init__(self, value = 42):... self.somevar = value...f = foobar('this is a test')f.somevar'this is a test'重写一般方法和特殊的构造方法每个类都可能有一个或者多个超类,它们从超类那里继承行为方式,如果一个方法在b类的一个实例中被调用,但在b类中没有找到该方法,那么就去它的超类a里面找class a:  def hello(self):    print "hello,i'am a."class b(a)a类定义了一个叫做hello的方法,被b类继承,下面是一个说明类是如何工作的列子A = a()B = b()A.hello()hello,i'am aB.hello()hello,i'am a因为b类没有定义自己的hello方法,所以当hello被调用的时候,原始的信息就被打印出来。在子类中增加功能的最基本的方法就是增加方法,但是也可以重写一些超类的方法来自定义继承的行为。b类也能重写这个方法,比如下面的列子中b类的定义被修改了。class b(a):  def hello(self):    print "hello,i'am b."重写是继承机制中的一个重要内容,对于构造方法尤其重要,构造方法用来初始化新创建的对象的状态,大多数子类不仅要拥有自己的初始化代码,还要拥有超类的初始化代码,虽然重写的机制对于所有方法来说都是一样的,但是当重写构造方法和普通重写方法更容易遇到特别的问题,比如,如果一个类的构造方法被重写,那么就需要调用超类的构造方法,否则,对象可能不会被正确的初始化。

ylrf1212 2019-12-02 01:08:46 0 浏览量 回答数 0

回答

触及 multiple inheritance (MI)(多继承)的时候,C++ 社区就会鲜明地分裂为两个基本的阵营。一个阵营认为如果 single inheritance (SI)(单继承)是有好处的,multiple inheritance(多继承)一定更有好处。另一个阵营认为 single inheritance(单继承)有好处,但是多继承引起的麻烦使它得不偿失。在本文中,我们的主要目的是理解在 MI 问题上的这两种看法。   首要的事情之一是要承认当将 MI 引入设计领域时,就有可能从多于一个的 base class(基类)中继承相同的名字(例如,函数,typedef,等等)。这就为歧义性提供了新的时机。例如: class BorrowableItem { // something a library lets you borrowpublic: void checkOut(); // check the item out from the library ..}; class ElectronicGadget {private: bool checkOut() const; // perform self-test, return whether ... // test succeeds}; class MP3Player: // note MI herepublic BorrowableItem, // (some libraries loan MP3 players)public ElectronicGadget{ ... }; // class definition is unimportant MP3Player mp; mp.checkOut(); // ambiguous! which checkOut?    注意这个例子,即使两个函数中只有一个是可访问的,对 checkOut 的调用也是有歧义的。(checkOut 在 BorrowableItem 中是 public(公有)的,但在 ElectronicGadget 中是 private(私有)的。)这与 C++ 解析 overloaded functions(重载函数)调用的规则是一致的:在看到一个函数的是否可访问之前,C++ 首先确定与调用匹配最好的那个函数。只有在确定了 best-match function(最佳匹配函数)之后,才检查可访问性。这目前的情况下,两个 checkOuts 具有相同的匹配程度,所以就不存在最佳匹配。因此永远也不会检查到 ElectronicGadget::checkOut 的可访问性。   为了消除歧义性,你必须指定哪一个 base class(基类)的函数被调用: mp.BorrowableItem::checkOut(); // ah, that checkOut...   当然,你也可以尝试显式调用 ElectronicGadget::checkOut,但这样做会有一个 "you're trying to call a private member function"(你试图调用一个私有成员函数)错误代替歧义性错误。    multiple inheritance(多继承)仅仅意味着从多于一个的 base class(基类)继承,但是在还有 higher-level base classes(更高层次基类)的 hierarchies(继承体系)中出现 MI 也并不罕见。这会导致有时被称为 "deadly MI diamond"(致命的多继承菱形)的后果。 class File { ... };class InputFile: public File { ... };class OutputFile: public File { ... };class IOFile: public InputFile,public OutputFile{ ... };    在一个“在一个 base class(基类)和一个 derived class(派生类)之间有多于一条路径的 inheritance hierarchy(继承体系)”(就像上面在 File 和 IOFile 之间,有通过 InputFile 和 OutputFile 的两条路径)的任何时候,你都必须面对是否需要为每一条路径复制 base class(基类)中的 data members(数据成员)的问题。例如,假设 File class 有一个 data members(数据成员)fileName。IOFile 中应该有这个 field(字段)的多少个拷贝呢?一方面,它从它的每一个 base classes(基类)继承一个拷贝,这就暗示 IOFile 应该有两个 fileName data members(数据成员)。另一方面,简单的逻辑告诉我们一个 IOFile object(对象)应该仅有一个 file name(文件名),所以通过它的两个 base classes(基类)继承来的 fileName field(字段)不应该被复制。   C++ 在这个争议上没有自己的立场。它恰当地支持两种选项,虽然它的缺省方式是执行复制。如果那不是你想要的,你必须让这个 class(类)带有一个 virtual base class(虚拟基类)的数据(也就是 File)。为了做到这一点,你要让从它直接继承的所有的 classes(类)使用 virtual inheritance(虚拟继承): class File { ... };class InputFile: virtual public File { ... };class OutputFile: virtual public File { ... };class IOFile: public InputFile,public OutputFile{ ... };    标准 C++ 库包含一个和此类似的 MI hierarchy(继承体系),只是那个 classes(类)是 class templates(类模板),名字是 basic_ios,basic_istream,basic_ostream 和 basic_iostream,而不是 File,InputFile,OutputFile 和 IOFile。   从正确行为的观点 看,public inheritance(公有继承)应该总是 virtual(虚拟)的。如果这是唯一的观点,规则就变得简单了:你使用 public inheritance(公有继承)的任何时候,都使用 virtual public inheritance(虚拟公有继承)。唉,正确性不是唯一的视角。避免 inherited fields(继承来的字段)复制需要在编译器的一部分做一些 behind-the-scenes legerdemain(幕后的戏法),而结果是从使用 virtual inheritance(虚拟继承)的 classes(类)创建的 objects(对象)通常比不使用 virtual inheritance(虚拟继承)的要大。访问 virtual base classes(虚拟基类)中的 data members(数据成员)也比那些 non-virtual base classes(非虚拟基类)中的要慢。编译器与编译器之间有一些细节不同,但基本的要点很清楚:virtual inheritance costs(虚拟继承要付出成本)。   它也有一些其它方面的成本。支配 initialization of virtual base classes(虚拟基类初始化)的规则比 non-virtual bases(非虚拟基类)的更加复杂而且更不直观。初始化一个 virtual base(虚拟基)的职责由 hierarchy(继承体系)中 most derived class(层次最低的派生类)承担。这个规则中包括的含义:   (1) 从需要 initialization(初始化)的 virtual bases(虚拟基)派生的 classes(类)必须知道它们的 virtual bases(虚拟基),无论它距离那个 bases(基)有多远;   (2) 当一个新的 derived class(派生类)被加入继承体系时,它必须为它的 virtual bases(虚拟基)(包括直接的和间接的)承担 initialization responsibilities(初始化职责)。    我对于 virtual base classes(虚拟基类)(也就是 virtual inheritance(虚拟继承))的建议很简单。首先,除非必需,否则不要使用 virtual bases(虚拟基)。缺省情况下,使用 non-virtual inheritance(非虚拟继承)。第二,如果你必须使用 virtual base classes(虚拟基类),试着避免在其中放置数据。这样你就不必在意它的 initialization(初始化)(以及它的 turns out(清空),assignment(赋值))规则中的一些怪癖。值得一提的是 Java 和 .NET 中的 Interfaces(接口)不允许包含任何数据,它们在很多方面可以和 C++ 中的 virtual base classes(虚拟基类)相比照。   现在我们使用下面的 C++ Interface class(接口类)(参见《C++箴言:最小化文件之间的编译依赖》)来为 persons(人)建模: class IPerson {public: virtual ~IPerson();  virtual std::string name() const = 0; virtual std::string birthDate() const = 0;};    IPerson 的客户只能使用 IPerson 的 pointers(指针)和 references(引用)进行编程,因为 abstract classes(抽象类)不能被实例化。为了创建能被当作 IPerson objects(对象)使用的 objects(对象),IPerson 的客户使用 factory functions(工厂函数)(再次参见 Item 31)instantiate(实例化)从 IPerson 派生的 concrete classes(具体类): // factory function to create a Person object from a unique database ID;// see Item 18 for why the return type isn't a raw pointerstd::tr1::shared_ptr makePerson(DatabaseID personIdentifier); // function to get a database ID from the userDatabaseID askUserForDatabaseID(); DatabaseID id(askUserForDatabaseID());std::tr1::shared_ptr pp(makePerson(id)); // create an object// supporting the// IPerson interface ... // manipulate *pp via// IPerson's member// functions   但是 makePerson 怎样创建它返回的 pointers(指针)所指向的 objects(对象)呢?显然,必须有一些 makePerson 可以实例化的从 IPerson 派生的 concrete class(具体类)。    假设这个 class(类)叫做 CPerson。作为一个 concrete class(具体类),CPerson 必须提供它从 IPerson 继承来的 pure virtual functions(纯虚拟函数)的 implementations(实现)。它可以从头开始写,但利用包含大多数或全部必需品的现有组件更好一些。例如,假设一个老式的 database-specific class(老式的数据库专用类)PersonInfo 提供了 CPerson 所需要的基本要素: class PersonInfo {public: explicit PersonInfo(DatabaseID pid); virtual ~PersonInfo();  virtual const char * theName() const; virtual const char * theBirthDate() const; ... private: virtual const char * valueDelimOpen() const; // see virtual const char * valueDelimClose() const; // below ...};    你可以看出这是一个老式的 class(类),因为 member functions(成员函数)返回 const char*s 而不是 string objects(对象)。尽管如此,如果鞋子合适,为什么不穿呢?这个 class(类)的 member functions(成员函数)的名字暗示结果很可能会非常合适。   你突然发现 PersonInfo 是设计用来帮助以不同的格式打印 database fields(数据库字段)的,每一个字段的值的开始和结尾通过指定的字符串定界。缺省情况下,字段值开始和结尾定界符是方括号,所以字段值 "Ring-tailed Lemur" 很可能被安排成这种格式: [Ring-tailed Lemur]   根据方括号并非满足 PersonInfo 的全体客户的期望的事实,virtual functions(虚拟函数)valueDelimOpen 和 valueDelimClose 允许 derived classes(派生类)指定它们自己的开始和结尾定界字符串。PersonInfo 的 member functions(成员函数)的 implementations(实现)调用这些 virtual functions(虚拟函数)在它们返回的值上加上适当的定界符。作为一个例子使用 PersonInfo::theName,代码如下: const char * PersonInfo::valueDelimOpen() const{ return "["; // default opening delimiter} const char * PersonInfo::valueDelimClose() const{ return "]"; // default closing delimiter} const char * PersonInfo::theName() const{ // reserve buffer for return value; because this is // static, it's automatically initialized to all zeros static char value[Max_Formatted_Field_Value_Length];  // write opening delimiter std::strcpy(value, valueDelimOpen());  append to the string in value this object's name field (being careful to avoid buffer overruns!)  // write closing delimiter std::strcat(value, valueDelimClose());  return value;}    有人可能会质疑 PersonInfo::theName 的陈旧的设计(特别是一个 fixed-size static buffer(固定大小静态缓冲区)的使用,这样的东西发生 overrun(越界)和 threading(线程)问题是比较普遍的——参见《C++箴言:必须返回对象时别返回引用》),但是请把这样的问题放到一边而注意这里:theName 调用 valueDelimOpen 生成它要返回的 string(字符串)的开始定界符,然后它生成名字值本身,然后它调用 valueDelimClose。   因为 valueDelimOpen 和 valueDelimClose 是 virtual functions(虚拟函数),theName 返回的结果不仅依赖于 PersonInfo,也依赖于从 PersonInfo 派生的 classes(类)。    对于 CPerson 的实现者,这是好消息,因为当细读 IPerson documentation(文档)中的 fine print(晦涩的条文)时,你发现 name 和 birthDate 需要返回未经修饰的值,也就是,不允许有定界符。换句话说,如果一个人的名字叫 Homer,对那个人的 name 函数的一次调用应该返回 "Homer",而不是 "[Homer]"。   CPerson 和 PersonInfo 之间的关系是 PersonInfo 碰巧有一些函数使得 CPerson 更容易实现。这就是全部。因而它们的关系就是 is-implemented-in-terms-of,而我们知道有两种方法可以表现这一点:经由 composition(复合)(参见《C++箴言:通过composition模拟“has-a”》)和经由 private inheritance(私有继承)(参见《C++箴言:谨慎使用私有继承》)。《C++箴言:谨慎使用私有继承》 指出 composition(复合)是通常的首选方法,但如果 virtual functions(虚拟函数)要被重定义,inheritance(继承)就是必不可少的。在当前情况下,CPerson 需要重定义 valueDelimOpen 和 valueDelimClose,所以简单的 composition(复合)做不到。最直截了当的解决方案是让 CPerson 从 PersonInfo privately inherit(私有继承),虽然 《C++箴言:谨慎使用私有继承》 说过只要多做一点工作,则 CPerson 也能用 composition(复合)和 inheritance(继承)的组合有效地重定义 PersonInfo 的 virtuals(虚拟函数)。这里,我们用 private inheritance(私有继承)。   但 是 CPerson 还必须实现 IPerson interface(接口),而这被称为 public inheritance(公有继承)。这就引出一个 multiple inheritance(多继承)的合理应用:组合 public inheritance of an interface(一个接口的公有继承)和 private inheritance of an implementation(一个实现的私有继承): class IPerson { // this class specifies thepublic: // interface to be implemented virtual ~IPerson();  virtual std::string name() const = 0; virtual std::string birthDate() const = 0;}; class DatabaseID { ... }; // used below; details are// unimportant class PersonInfo { // this class has functionspublic: // useful in implementing explicit PersonInfo(DatabaseID pid); // the IPerson interface virtual ~PersonInfo();  virtual const char * theName() const; virtual const char * theBirthDate() const;  virtual const char * valueDelimOpen() const; virtual const char * valueDelimClose() const; ...}; class CPerson: public IPerson, private PersonInfo { // note use of MIpublic: explicit CPerson( DatabaseID pid): PersonInfo(pid) {} virtual std::string name() const // implementations { return PersonInfo::theName(); } // of the required // IPerson member virtual std::string birthDate() const // functions { return PersonInfo::theBirthDate(); }private: // redefinitions of const char * valueDelimOpen() const { return ""; } // inherited virtual const char * valueDelimClose() const { return ""; } // delimiter}; // functions   在 UML 中,这个设计看起来像这样:   这个例子证明 MI 既是有用的,也是可理解的。    时至今日,multiple inheritance(多继承)不过是 object-oriented toolbox(面向对象工具箱)里的又一种工具而已,典型情况下,它的使用和理解更加复杂,所以如果你得到一个或多或少等同于一个 MI 设计的 SI 设计,则 SI 设计总是更加可取。如果你能拿出来的仅有的设计包含 MI,你应该更加用心地考虑一下——总会有一些方法使得 SI 也能做到。但同时,MI 有时是最清晰的,最易于维护的,最合理的完成工作的方法。在这种情况下,毫不畏惧地使用它。只是要确保谨慎地使用它。   Things to Remember   ·multiple inheritance(多继承)比 single inheritance(单继承)更复杂。它能导致新的歧义问题和对 virtual inheritance(虚拟继承)的需要。    ·virtual inheritance(虚拟继承)增加了 size(大小)和 speed(速度)成本,以及 initialization(初始化)和 assignment(赋值)的复杂度。当 virtual base classes(虚拟基类)没有数据时它是最适用的。   ·multiple inheritance(多继承)有合理的用途。一种方案涉及组合从一个 Interface class(接口类)的 public inheritance(公有继承)和从一个有助于实现的 class(类)的 private inheritance(私有继承)。 关于虚拟继承的思考虚拟继承在一般的应用中很少用到,所以也往往被忽视,这也主要是因为在C++中,多重继承是不推荐的,而一旦离开了多重继承,虚拟继承就完全失去了存在的必要(因为这样只会降低效率和占用更多的空间,实在是一无是处)。  以下面的一个例子为例:  #include   #include   class CA  {   int k; //为了便于说明后面的内存结构特别添加  public:   void f() {cout << "CA::f" << endl;}  };  class CB : public CA  {  };  class CC : public CA  {  };  class CD : public CB, public CC  {  };  void main()  {   CD d;   d.f();  }  当编译上述代码时,我们会收到如下的错误提示:  error C2385: 'CD::f' is ambiguous  即编译器无法确定你在d.f()中要调用的函数f到底是哪一个。这里可能会让人觉得有些奇怪,命名只定义了一个CA::f,既然大家都派生自CA,那自然就是调用的CA::f,为什么还无法确定呢?  这是因为编译器在进行编译的时候,需要确定子类的函数定义,如CA::f是确定的,那么在编译CB、CC时还需要在编译器的语法树中生成CB::f,CC::f等标识,那么,在编译CD的时候,由于CB、CC都有一个函数f,此时,编译器将试图生成两个CD::f标识,显然这时就要报错了。(当我们不使用CD::f的时候,以上标识都不会生成,所以,如果去掉d.f()一句,程序将顺利通过编译)  要解决这个问题,有两个方法:  1、重载函数f():此时由于我们明确定义了CD::f,编译器检查到CD::f()调用时就无需再像上面一样去逐级生成CD::f标识了;  此时CD的元素结构如下:  --------  |CB(CA)|  |CC(CA)|  --------  故此时的sizeof(CD) = 8;(CB、CC各有一个元素k)  2、使用虚拟继承:虚拟继承又称作共享继承,这种共享其实也是编译期间实现的,当使用虚拟继承时,上面的程序将变成下面的形式:  #include   #include   class CA  {   int k;  public:   void f() {cout << "CA::f" << endl;}  };  class CB : virtual public CA  {  };  class CC : virtual public CA  {  };  class CD : public CB, public CC  {  };  void main()  {   CD d;   d.f();  }  此时,当编译器确定d.f()调用的具体含义时,将生成如下的CD结构:  ----  |CB|  |CC|  |CA|  ----  同时,在CB、CC中都分别包含了一个指向CA的vbptr(virtual base table pointer),其中记录的是从CB、CC的元素到CA的元素之间的偏移量。此时,不会生成各子类的函数f标识,除非子类重载了该函数,从而达到“共享”的目的。  也正因此,此时的sizeof(CD) = 12(两个vbptr + sizoef(int));

a123456678 2019-12-02 01:58:07 0 浏览量 回答数 0

回答

简单来说,类是一种高级抽象,就是一种高级的数据类型,是对象的蓝图,就是用来定义你要用的对象的属性和行为的,为什么要使用类,你可以和之前没有类的时候进行比较,比如和结构化编程比较,有了类有什么好处,总结就是封装、继承、多态。希望我的答案能够帮助到你,答案满意还请采纳,谢谢。

大财主 2019-12-02 01:06:33 0 浏览量 回答数 0

回答

面向对象有三个特征:封装、继承、多态。 其中继承和实现都体现了传递性。而且明确定义如下: 继承:如果多个类的某个部分的功能相同,那么可以抽象出一个类出来,把他们的相同部分都放到父类里,让他们都继承这个类。 实现:如果多个类处理的目标是一样的,但是处理的方法方式不同,那么就定义一个接口,也就是一个标准,让他们的实现这个接口,各自实现自己具体的处理方法来处理那个目标 所以,继承的根本原因是因为要复用,而实现的根本原因是需要定义一个标准。 在Java中,继承使用extends关键字实现,而实现通过implements关键字。 Java中支持一个类同时实现多个借口,但是不支持同时继承多个类。 简单点说,就是同样是一台汽车,既可以是电动车,也可以是汽油车,也可以是油电混合的,只要实现不同的标准就行了,但是一台车只能属于一个品牌,一个厂商。 class Car extends Benz implements GasolineCar, ElectroCar{ } 在接口中只能定义全局常量(static final)和无实现的方法(Java 8以后可以有defult方法);而在继承中可以定义属性方法,变量,常量等。

montos 2020-06-01 15:50:19 0 浏览量 回答数 0

回答

继承是对已有的类做一番改造,以此获得一个特殊的版本。简而言之,就是将一个较为抽象的类改造成能适用于某些特定需求的类。因此,对于Wolf和Animal的关系,使用继承更能表达其现实意义。用一个动物来合成一匹狼毫无意义:狼并不是由动物组成的。反之,如果两个类之间有明确的整体、部分的关系,例如Person类需要复用Arm类的方法(Person对象由Arm对象组合而成),此时就应该采用组合关系来实现复用,把Arm作为Person类的嵌入Field,借助于Arm的方法来实现Person的方法,这是一个不错的选择。

星尘linger 2020-04-07 12:51:18 0 浏览量 回答数 0

问题

求java大神戳入,关于java多态的问题~求指导!:报错

kun坤 2020-06-10 09:25:06 0 浏览量 回答数 1

回答

final关键字,可用来修饰域,方法,和类 第一种情况,final修饰类,表示最终类,不可以被继承,final类里的方法默认为final方法,不可以被覆写 第二种情况,final修饰方法,方法不能被覆写,private方法默认为final方法。Java早期为效率问题引出final方法,但现在发现存在诸多毛病,不推荐使用 第三种情况,final修饰域,final修饰域又分为修饰基本类型域和修饰对象 final修饰基本类型域,一旦初始化,数值保持不变 final修饰引用类型域,一旦初始化,则引用对象的地址不再发生变化,但是对象的内容可以改变

蛮大人123 2019-12-02 02:25:17 0 浏览量 回答数 0
阿里云大学 云服务器ECS com域名 网站域名whois查询 开发者平台 小程序定制 小程序开发 国内短信套餐包 开发者技术与产品 云数据库 图像识别 开发者问答 阿里云建站 阿里云备案 云市场 万网 阿里云帮助文档 免费套餐 开发者工具 企业信息查询 小程序开发制作 视频内容分析 企业网站制作 视频集锦 代理记账服务 2020阿里巴巴研发效能峰会 企业建站模板 云效成长地图 高端建站 阿里云双十一主会场 阿里云双十一新人会场 1024程序员加油包 阿里云双十一拼团会场 场景化解决方案 阿里云双十一直播大厅