精华内容
下载资源
问答
  • 面向对象编程三个基本特征

    万次阅读 2016-04-22 13:50:51
    三个基本特征面向对象三个基本特征是:封装、继承、多态。封装封装最好理解了。封装是面向对象特征之一,是对象和类概念的主要特性。 封装,也就是把客观事物封装成抽象的类,并且类可以把自己的数据和方法只让...

    基本特征

    面向对象的三个基本特征是:封装继承多态

    封装

    封装最好理解了。封装是面向对象的特征之一,是对象和类概念的主要特性。
    封装,也就是把客观事物封装成抽象的类,并且类可以把自己的数据和方法只让可信的类或者对象操作,对不可信的进行信息隐藏。

    继承

    面向对象编程 (OOP) 语言的一个主要功能就是“继承”。继承是指这样一种能力:它可以使用现有类的所有功能,并在无需重新编写原来的类的情况下对这些功能进行扩展。
    通过继承创建的新类称为“子类”或“派生类”。
    被继承的类称为“基类”、“父类”或“超类”。
    继承的过程,就是从一般到特殊的过程。
    要实现继承,可以通过“继承”(Inheritance)和“组合”(Composition)来实现。
    在某些 OOP 语言中,一个子类可以继承多个基类。但是一般情况下,一个子类只能有一个基类,要实现多重继承,可以通过多级继承来实现。

    继承概念的实现方式有三类:实现继承、接口继承和可视继承。

    • 实现继承是指使用基类的属性和方法而无需额外编码的能力;
    • 接口继承是指仅使用属性和方法的名称、但是子类必须提供实现的能力;
    • 可视继承是指子窗体(类)使用基窗体(类)的外观和实现代码的能力;

    在考虑使用继承时,有一点需要注意,那就是两个类之间的关系应该是“属于”关系。例如,Employee 是一个人,Manager 也是一个人,因此这两个类都可以继承 Person 类。但是 Leg 类却不能继承 Person 类,因为腿并不是一个人。

    抽象类仅定义将由子类创建的一般属性和方法,创建抽象类时,请使用关键字 Interface 而不是 Class。
    OO开发范式大致为:划分对象→抽象类→将类组织成为层次化结构(继承和合成) →用类与实例进行设计和实现几个阶段。

    多态

    1、概念
    多态性(polymorphisn)是允许你将父对象设置成为和一个或更多的他的子对象相等的技术,赋值之后,父对象就可以根据当前赋值给它的子对象的特性以不同的方式运作。简单的说,就是一句话:允许将子类类型的指针赋值给父类类型的指针。

    2、实现方式
    实现多态,有二种方式,覆盖,重载。

    3、覆盖(Override)
    覆盖,是指子类重新定义父类的虚函数的做法。它是覆盖了一个方法并且对其重写,以求达到不同的作用。对我们来说最熟悉的覆盖就是对接口方法的实现,在接口中一般只是对方法进行了声明,而我们在实现时,就需要实现接口声明的所有方法。除了这个典型的用法以外,我们在继承中也可能会在子类覆盖父类中的方法。在覆盖要注意以下的几点:
    1、覆盖的方法的标志必须要和被覆盖的方法的标志完全匹配,才能达到覆盖的效果;
    2、覆盖的方法的返回值必须和被覆盖的方法的返回一致;
    3、覆盖的方法所抛出的异常必须和被覆盖方法的所抛出的异常一致,或者是其子类;
    4、被覆盖的方法不能为private,否则在其子类中只是新定义了一个方法,并没有对其进行覆盖。

    4、重载(Overload)
    重载,是指允许存在多个同名函数,而这些函数的参数表不同(或许参数个数不同,或许参数类型不同,或许两者都不同)。它是指我们可以定义一些名称相同的方法,通过定义不同的输入参数来区分这些方法,然后再调用时,VM就会根据不同的参数样式,来选择合适的方法执行。在使用重载要注意以下的几点:

    1. 在使用重载时只能通过不同的参数样式。例如,不同的参数类型,不同的参数个数,不同的参数顺序(当然,同一方法内的几个参数类型必须不一样,例如可以是fun(int,float),但是不能为fun(int,int));
    2. 不能通过访问权限、返回类型、抛出的异常进行重载;
    3. 方法的异常类型和数目不会对重载造成影响;
    4. 对于继承来说,如果某一方法在父类中是访问权限是priavte,那么就不能在子类对其进行重载,如果定义的话,也只是定义了一个新方法,而不会达到重载的效果。

    5、区别
    其实,重载的概念并不属于“面向对象编程”,重载的实现是:编译器根据函数不同的参数表,对同名函数的名称做修饰,然后这些同名函数就成了不同的函数(至少对于编译器来说是这样的)。如,有两个同名函数:function func(p:integer):integer;和function func(p:string):integer;。那么编译器做过修饰后的函数名称可能是这样的:int_func、str_func。对于这两个函数的调用,在编译器间就已经确定了,是静态的(记住:是静态)。也就是说,它们的地址在编译期就绑定了(静态绑定),因此,重载和多态无关!真正和多态相关的是“覆盖”。当子类重新定义了父类的虚函数后,父类指针根据赋给它的不同的子类指针,动态(记住:是动态!)的调用属于子类的该函数,这样的函数调用在编译期间是无法确定的(调用的子类的虚函数的地址无法给出)。因此,这样的函数地址是在运行期绑定的(动态绑定)。

    结论就是:重载只是一种语言特性,与多态无关,与面向对象也无关!引用一句Bruce Eckel的话:“不要犯傻,如果它不是晚邦定,它就不是多态。”

    6、作用
    我们知道,封装可以隐藏实现细节,使得代码模块化;继承可以扩展已存在的代码模块(类);它们的目的都是为了——代码重用。而多态则是为了实现另一个目的——接口重用!多态的作用,就是为了类在继承和派生的时候,保证使用“家谱”中任一类的实例的某一属性时的正确调用。

    展开全文
  • 面向对象编程特征

    千次阅读 2019-04-10 20:42:12
    面向对象编程特征:封装、继承、多态 一:封装 对于封装而言,一对象它所封装的是自己的属性和方法,所以他是不需要依赖其他对象就可以完成自己的操作。 封装的大好处: 1、良好的封装能够减少耦合。 2、...

    面向对象编程的三大特征:封装、继承、多态

    一:封装
    对于封装而言,一个对象它所封装的是自己的属性和方法,所以他是不需要依赖其他对象就可以完成自己的操作。
    封装的三大好处:
    1、良好的封装能够减少耦合。
    2、类内部的结构可以自由修改。
    3、可以对成员进行更精确的控制。
    4、隐藏信息,实心细节。
    封装可以使我们容易的修改类的内部实现,二无需修改使用了该类的客户代码。
    二:继承
    继承是使用已存在的类定义作为基础建立新类的技术,新类的定义课增加新的数据或新的功能,也可以用父类的功能,但不能选择性的继承父类。
    继承定义了类如何相互关联,共享特征。对于若干相同或者相识的类,我们可以抽象出他们共有的行为或者属相并且将其定义成一个父类或者超类,然后用这些类继承改父类,他们不仅可以拥有父类的属性,方法,还可以定义自己独有的属性或者方法。
    继承需要记住三句话:
    1、子类拥有父类非private的属性和方法。
    2、子类可以拥有自己的属性和方法,即子类可以对父类进行扩展。
    3、子类可以用自己的方式实现父类的方法。
    继承少不了三个东西:构造器、protected关键字、向上转型
    构造器(Constructor):
    除了private的属性和方法不能被继承,还有一样子类继承不了------构造器。构造器只能被调动,不能被继承,调用父类的构造器方法,我们使用super()即可。

    对于继承,子类会默认调用父类的构造器,但是如果没有默认的父类构造器,子类必须显示的指定父类的构造器,而且必须是在子类构造器中做的第一件事。

    在讲继承的时候我们就知道父类的私有属性和构造方法并不能被继承,所以 Constructor 也就不能被 override(重写),但是可以 overload(重载),所以你可以看到一个类中有多个构造函数的情况。

    protected关键字:
    对于protected而言,他指明就类用户而言,他是private,但是对于任何继承与此类的子类而言或者其他任何位于同一个包的类而言,他确实可以访问的。
    三:多态
    实现多态有三个必要条件:继承,重写,向上转型
    继承:在多态中必须存在有继承关系的子类和父类。
    重写:子类对父类中某些方法进行重新定义,在调用者些方法时就会调用子类的方法。
    向上转型:在多态中需要将子类的引用赋给父类对象,只有这样改引用才能够具备既能调用父类的方法和子类的方法。
    多态问题????????????
    两个子类A\B继承了父类,A子类要进行微小改变,B子类不需要改变,完全继承父类。所以对A积蓄方法重写,不完全继承父类,从而实现多态。
    实现形式:
    在Java中两种形式可以实现多态:继承和接口
    基于继承实现多态:
    实现机制主要表现在父类和继承该父类的一个或者多个子类对某些方法的重写,多个子类对同一方法重现可以表现不同的行为。
    当子类重写父类的方法被调用时,只有对象继承链中最末端的方法才会被调用。
    对于应用子类的父类类型,在吹引用时,他适用于继承该福诶的所有子类,子类对象不同,对方法的实现也就不同,执行相同动作产生的行为也就不同。
    如果父类是抽象类,那么子类必须实现父类中所有的抽象方法,这样改父类所有的子类一定存在同一的对外接口,但其内部的具体实现可以各异。这样我们就可以使用顶层类提供的同意接口处理该层次的方法。

      基于接口实现多态:
      继承是通过重写父类的同一方法的几个不同子类来体现的,那么就是通过实现接口并覆盖接口同一方法的几个不同类体现的。
      在接口的多态中,只想接口引用必须是指定这实现了接口的一个类的实例程序,在运行时,根据对象引用的实际类型来执行对应的方法。
    

    继承都是单继承,只能为一组相关的类提供一致的服务接口。但是接口可以是多继承,多实现,他能够录用一组相关或者不相关的接口进行组合与扩充,能够对外提供一致的服务接口。

    重载和重写的区别?

    • 重载: 发生在同一个类中,方法名必须相同,参数类型不同、个数不同、顺序不同,方法返回值和访问修饰符可以不同,发生在编译时。

    • 重写: 发生在父子类中,方法名、参数列表必须相同,返回值范围小于等于父类,抛出的异常范围小于等于父类,访问修饰符范围大于等于父类;如果父类方法访问修饰符为 private 则子类就不能重写该方法。

    展开全文
  • Java面向对象编程三特征 - 多态

    千次阅读 多人点赞 2020-04-06 11:43:48
    本文关键字:Java、面向对象、特征、多态。多态是面向对象编程特征之一,是面向对象思想的终极体现之一。在理解多态之前需要先掌握继承、重写、父类引用指向子类对象的相关概念。

    写在前面:博主是一只经过实战开发历练后投身培训事业的“小山猪”,昵称取自动画片《狮子王》中的“彭彭”,总是以乐观、积极的心态对待周边的事物。本人的技术路线从Java全栈工程师一路奔向大数据开发、数据挖掘领域,如今终有小成,愿将昔日所获与大家交流一二,希望对学习路上的你有所助益。同时,博主也想通过此次尝试打造一个完善的技术图书馆,任何与文章技术点有关的异常、错误、注意事项均会在末尾列出,欢迎大家通过各种方式提供素材。

    • 对于文章中出现的任何错误请大家批评指出,一定及时修改。
    • 有任何想要讨论和学习的问题可联系我:zhuyc@vip.163.com。
    • 发布文章的风格因专栏而异,均自成体系,不足之处请大家指正。

    Java面向对象编程三大特征 - 多态

    本文关键字:Java、面向对象、三大特征、多态


    多态是面向对象编程的三大特征之一,是面向对象思想的终极体现之一。在理解多态之前需要先掌握继承、重写、父类引用指向子类对象的相关概念,对继承还没有完全明白的同学可进传送门:Java面向对象编程三大特征 - 继承

    一、抽象类

    在继承中,我们已经了解了子父类的关系以及如何对子父类进行设计,如果已经存在多个实体类,再去定义父类其实是不断的抽取公共重合部分的过程,如果有需要将会产生多重继承关系。在抽取整理的过程中,除了属性可以复用,有很多方法一样也可以复用,假如以图形举例:矩形、圆形,都可以具有周长和面积两个方法,但是计算的方式完全不同,矩形和圆形之间肯定不能构成子父类关系,那么只能是同时去继承一个父类,那么问题就来了,这两个类都有什么共同点?

    除了都是图形好像并没有什么共同点,矩形有两组边长,圆形是通过半径来描述,如果非要往一起联系的话。。。Wait a moment(灵光一闪中,请勿打扰)!!!难道说是都可以计算出周长和面积?细细想来,也是能说出一番道理的,但是这好抽象啊!
    如果真的是这样,也只能有一个模糊的思路,既然描述图形的属性不能够共用那就分别放在两个子类中吧,那么计算周长和面积的方法要怎么搞?如果在父类中定义相应的方法,那参数列表怎么写?方法体怎么填?这个坑好像有点大,接下来,我们就要华丽地将这个坑填平。

    1. 抽象与抽象类

    在上面的例子中,我们遇到了一个情况,有两个在逻辑上看似相关的类,我们想要把他们联系起来,因为这样做可以提高效率,但是在实施的过程中发现这个共同点有点太过模糊,难以用代码描述,甚至于还不如分开用来的方便,这时就要引出抽象的概念,对应的关键词为:abstract。

    • abstract可以修饰方法,修饰后被称为抽象方法
    • abstract可以修饰类,修饰后被称为抽象类
    • abstract不能与static修饰符同时使用
    • abstract不能与final修饰符同时使用

    那么使用了abstract又能如何呢?这代表指定的方法和类很难表述,那么。。。就不用表述了!对于矩形类(Rectangle)与圆形类(Circle)的父类:图形类(Figure),我们只能总结出他具有计算周长和面积的方法,而具体的实现方法我们无法给出,只有明确了图形之后,才能给出具体的实现,于是我们使用抽象来描述这两个方法,被abstract修饰的方法不需要有方法体,且不能为private,由于抽象方法没有方法体,那么如果被代码调用到了怎么办呢?以下两个限制规则可以杜绝这个问题:

    • 抽象方法只能存在于抽象类中(接口在另外的文章中讨论)
    • 抽象类无法被直接实例化(匿名内部类的用法暂不做讨论)

    既然抽象类不能被实例化,那么自然也就不会调用到没有方法体的那些方法了,那这些方法该怎么被调用呢?我们需要一步一步的来梳理,至少目前我们已经能够清晰的得到如下的关系图了:

    2. 抽象类的特点

    抽象类的本质依然是一个类(class),所以具备着一个普通类的所有功能,包括构造方法等的定义,总结一下,抽象类具有以下的几个特点:

    • 抽象类由abstract修饰
    • 抽象类中允许出现抽象方法
    • 抽象类不能通过构造器直接实例化
    • 可以在抽象类中定义普通方法供子类继承

    现在,我们已经可以将抽象父类用代码描述出来:

    // 定义抽象类:图形类
    public abstract class Figure{
        // 定义计算周长的抽象方法:getC()
        public abstract double getC();
        // 定义计算面积的抽象方法:getS()
        public abstract double getS();
        // 定义描述图形的非抽象方法:print()
        public void print(){
            System.out.println("这是一个图形");
        }
    }
    

    3. 天生的父类:抽象类

    现在我们已经有了一个抽象类,其中也定义了抽象方法,抽象类不能被直接实例化保证了抽象方法不会被直接调用到。回忆一下我们的出发点,费劲巴力的弄出个抽象类就是为了提取出两个类比较抽象的共同点,那么下一步自然是继承了。

    • 抽象类不能直接实例化,是天生的抽象类
    • 如果一个类继承了抽象类,那么必须重写父类中的抽象方法
    • 如果抽象类中定义了构造方法,可以被子类调用或在实例化子类对象时执行
    • 如果抽象类的子类依然是抽象类,可以不重写抽象方法,将重写操作留给下一级子类

    二、重写

    重写指的是子父类之间方法构成的关系,当子类继承父类时,父类中可能已经存在了某些方法,那么子类实例就可以直接进行调用。在有些时候由于子父类之间的差异,对于已经存在的方法想要做一些修改,这个时候我们可以利用重写,在子类中定义一个与父类中的方法完全相同的方法,包括返回值类型和方法签名(方法名 + 参数列表),此时就会构成重写。这样,子类实例在调用方法时就可以覆盖父类中的方法,具体的过程在后半部分阐述。

    1. 重写与重载的区别

    我们在刚开始接触方法的时候了解到了一个概念:重载,与重写有些类似,容易混淆,如果知识点已经模糊可以进传送门:Java程序的方法设计。总结一下,重写和重载有以下区别:

    • 重载是同一个类中方法与方法之间的关系
    • 重写是子父类间(接口与实现类间)方法与方法之间的关系
    • 构成重载:方法名相同,参数列表不同,返回值类型可以不同
    • 构成重写:方法名相同,参数列表相同,返回值类型相同或为对应类型的子类
    • 构成重载的方法之间权限修饰符可以不同
    • 重写方法的权限修饰符一定要大于被重写方法的权限修饰符

    有关于权限修饰符的作用如果不明确可以进传送门:Java面向对象编程三大特征 - 封装。明确了重写的含义之后,我们终于可以再度提笔,完成我们之前的例子:

    // 定义矩形类
    public class Rectangle extends Figure{
        // 定义构造器
        public Rectangle(double height, double width) {
    		this.height = height;
    		this.width = width;
    	}
        // 定义长和宽
        public double height;
        public double width;
    
        // 重写计算周长方法
        @Override
    	public double getC() {
    		return 2 * (this.height + this.width);
    	}
    
        // 重写计算面积方法
    	@Override
    	public double getS() {
    		return this.height + this.width;
    	}
    
        // 可选覆盖
        @Override
    	public void print(){
            System.out.println("矩形");
        }
    }
    
    // 定义圆形类
    public class Circle extends Figure{
        // 定义构造器
        public Circle(double radius) {
    		this.radius = radius;
    	}
    
        // 定义半径
    	public double radius;
    	
        // 重写计算周长方法
    	@Override
    	public double getC() {
    		return 2 * Math.PI * this.radius;
    	}
    
        // 重写计算面积方法
    	@Override
    	public double getS() {
    		return Math.PI * Math.pow(this.radius, 2);
    	}
    
        // 可选覆盖
        @Override
    	public void print(){
            System.out.println("圆形");
        }
    }
    

    2. 方法重写的规则

    • 重写的标识为@Override
    • 方法的重写发生在子类或者接口的实现类中
    • 被final声明的方法不能被重写
    • 被static声明的方法不能被重写,只能声明同结构的静态方法,但是此时不构成重写
    • 受限于权限修饰符,子类可能只能重写部分父类中的方法

    3. 父类方法的显式调用

    从上面的代码中可以看到,子类继承父类后,如果存在抽象方法则比如重写,由于父类中的方法是抽象的,所以无法调用。对于普通的方法,可以选择性的重写,一旦重写我们可以认为父类的方法被覆盖了,其实这样的形容是不准确的,在初学阶段可以认为是覆盖。
    比较规范的说法是:通过子类实例无法直接调用到父类中的同名方法了,但是在内存中依然存在着父类方法的结构,只不过访问不到而已。另外,我们同样可以在子类中显式的调用出父类方法,这要用到super关键字。

    • super指代父类对象
    • super可以调用可访问的父类成员变量
    • super可以调用可访问的父类成员方法
    • super可以调用可访问的父类构造方法
    • 不能使用super调用父类中的抽象方法
    • 可以使用super调用父类中的静态方法

    如果我们需要在子类中调用父类方法或构造器,可以将代码修改如下:

    // 定义抽象类:图形类
    public abstract class Figure{
        // 在抽象类中定义构造器,在子类实例创建时执行
        public Figure(){
            System.out.println("Figure init");
        }
        // 定义计算周长的抽象方法:getC()
        public abstract double getC();
        // 定义计算面积的抽象方法:getS()
        public abstract double getS();
        // 定义描述图形的非抽象方法:print()
        public void print(){
            System.out.println("这是一个图形");
        }
    }
    
    // 定义矩形类
    public class Rectangle extends Figure{
        // 定义构造器
        public Rectangle(double height, double width) {
            super();// 会调用默认的无参构造,代码可省略
            this.height = height;
            this.width = width;
    	}
        // 定义长和宽
        public double height;
        public double width;
    
        // 重写计算周长方法
        @Override
    	public double getC() {
    		return 2 * (this.height + this.width);
    	}
    
        // 重写计算面积方法
    	@Override
    	public double getS() {
    		return this.height + this.width;
    	}
    
        // 可选覆盖
        @Override
    	public void print(){
            super.print();// 调用父类方法
            System.out.println("矩形");
        }
    }
    
    // 定义圆形类
    public class Circle extends Figure{
        // 定义构造器
        public Circle(double radius) {
            super();// 会调用默认的无参构造,代码可省略
            this.radius = radius;
    	}
    
        // 定义半径
    	public double radius;
    	
        // 重写计算周长方法
    	@Override
    	public double getC() {
    		return 2 * Math.PI * this.radius;
    	}
    
        // 重写计算面积方法
    	@Override
    	public double getS() {
    		return Math.PI * Math.pow(this.radius, 2);
    	}
    
        // 可选覆盖
        @Override
    	public void print(){
            super.print();// 调用父类方法
            System.out.println("圆形");
        }
    }
    

    三、父类引用指向子类对象

    前面提到的概念消化完毕后,我们看一下子父类对象实例化的形式以及方法的执行效果。

    1. 父类引用指向父类对象

    如果父类是一个抽象类,则在等号右侧不能直接使用new加构造方法的方式实例化,如果一定要得到父类实例,就要使用匿名内部类的用法,这里不做讨论。
    如果父类是一个普通类,那么我们在初始化时,等号左侧为父类型引用,等号右侧为父类型对象(实例),这个时候其实和我们去创建一个类的对象并没有什么分别,不需要想着他是某某类的父类,因为此时他不会和任何子类产生关系,只是一个默认继承了Object类的普通类,正常使用就好,能调用出的内容也都是父类中已定义的。

    2. 子类引用指向子类对象

    在进行子类实例化时,由于在子类的定义中继承了父类,所以在创建子类对象时,会先一步创建父类对象。在进行调用时,根据权限修饰符,可以调用出子类及父类中可访问的属性和方法。

    public class Test{
        public static void main(String[] args){
            Rectangle rectangle = new Rectangle(5,10);
            // 调用Rectangle中定义的方法,以子类重写为准
            rectangle.print();
            System.out.println(rectangle.getC());// 得到矩形周长
            System.out.println(rectangle.getS());// 得到矩形面积
            Circle circle = new Circle(5);
            // 调用Circle中定义的方法,以子类重写为准
            circle.print();
            System.out.println(circle.getC());// 得到圆形周长
            System.out.println(circle.getS());// 得到圆形面积
        }
    }
    

    3. 引用与对象之间的关系

    在刚开始学习编程时,我们接触了基本数据类型,可以直接用关键字声明,定义变量赋值后使用,并不需要使用new关键字。对于引用与对象的关系可以先参考之前的文章回顾一下:Java中的基本操作单元 - 类和对象。在这里我们重点要说明的是:等号左侧的引用部分,与等号右侧的部分在程序运行层面有怎样的关联。
    与基本数据类型不同,在类中可以定义各种属性和方法,使用时也需要先创建对象。等号左侧的部分依然是一个类型的声明,未赋值时虽然默认情况下是null,但在程序编译运行时,也会在栈中进行存储,记录了相应的结构信息,他所指向的对象必须是一个和它兼容的类型。
    类的声明引用存放在栈中,实例化得到的对象存放在堆中

    • 在代码编写阶段,能够调用出的内容以等号左侧类型为准
    • 在程序运行阶段,具体的的执行效果以等号右侧实例为准

    下图为引用与实例在内存中的关系示意图,有关于Java对象在内存中的分布将在另外的文章中说明:

    4. 父类引用指向子类对象

    了解了引用与对象的关系之后,就有了一个疑问,如果等号左侧的声明类型与等号右侧的实例类型不一致会怎么样呢?如果我们要保证程序能够通过编译,并且顺利执行,必须要保证等号两边的类型是兼容的。完全不相关的两个类是不能够出现在等号左右两边的,即使可以使用强制类型转换通过编译,在运行时依然会抛出异常。
    于是我们就联想到了子父类是否有可能进行兼容呢?会有两种情况:子类引用指向父类对象,父类引用指向子类对象,下面我们来一一讨论。

    • 子类引用指向父类对象为什么无法使用

    子类引用指向父类对象指的是:等号左侧为子类型的声明定义,等号右侧为父类型的实例。首先,结论是这种用法是不存在的,我们从两方面来分析原因。
    第一个方面,是否符合逻辑?也就是是否会有某种需求,让Java语言为开发者提供这样一种用法?显然是否定的,我们定义子类的目的就是为了扩展父类的功能,结果现在我们却在用老旧的、功能贫乏的父类实例(等号右侧)去满足已经具备了强劲的、功能更为强大的子类声明(等号左侧)的需要,这显然是不合理的。
    另一方面,在程序运行时是否能够办到?如果我们真的写出了相关的代码,会要求我们添加强制转换的语句,否则无法通过编译,即使通过,在运行时也会提示无法进行类型转换。这就相当于把一个只能打电话发短信的老人机强制转换为能安装各种APP的智能机,这显然是办不到的。

    • 父类引用指向子类对象有什么样的意义

    父类引用指向子类对象指的是:等号左侧为父类型的定义,等号右侧为子类型的实例。这种情况是会被经常使用的,类似的还有:接口指向实现类。那么,这种用法应该如何解释,又为什么要有这样的用法呢?
    首先,我们先来理解一下这代表什么含义,假如:父类为图形,子类为矩形和圆形。这就好比我声明了一个图形对象,这个时候我们知道,可以调用出图形类中定义的方法,由于图形类是一个抽象类,是不能直接实例化的,我们只能用他的两个子类试试看。

    public class Test{
        public static void main(String[] args){
            // figure1指向Rectangle实例
            Figure figure1 = new Rectangle(5,10);
            System.out.println(figure1.getC());// 得到矩形周长
            System.out.println(figure1.getS());// 得到矩形面积
            // figure2指向Circle实例
            Figure figure2 = new Circle(5);
            System.out.println(figure2.getC());// 得到圆形周长
            System.out.println(figure2.getS());// 得到圆形面积
        }
    }
    

    从上面的结果来看,这好像和子类引用指向子类对象的执行效果没什么区别呀?但是需要注意此时使用的是父类的引用,区别就在于,如果我们在子类中定义了独有的内容,是调用不到的。在上面已经解释了运行效果以等号右侧的实例为准,所以结果与直接创建的子类实例相同并不难理解。
    重点要说明一下其中的含义:使用Figure(图形)声明,代表我现在只知道是一个图形,知道能执行哪些方法,如果再告知是一个矩形,那就能算出这个矩形的周长和面积;如果是一个圆形,那就能算出这个圆形的周长和面积。我们也可以这样去描述:这个图形是一个矩形或这个图形是一个圆形。
    如果从程序运行的角度去解释,我们已经知道,子类对象在实例化时会先实例化父类对象,并且,如果子类重写了父类的方法,父类的方法将会隐藏。如果我们用一个父类引用去指向一个子类对象,这就相当于对象实例很强大,但是我们只能启用部分的功能,但是有一个好处就是相同的指令,不同的子类对象都能够执行,并且会存在差异。这就相当于一部老人机,只具备打电话和发短信的功能,小米手机和魅族手机都属于升级扩展后的智能机,当然保有手机最基本的通讯功能,这样使用是没问题的。

    四、多态

    学习了上面的内容后,其实你已经掌握了多态的用法,现在我们来明确总结一下。

    1. 什么是多态

    多态指的是同一个父类,或同一个接口,发出了一个相同的指令(调用了同一个方法),由于具体执行的实例(子类对象或实现类对象)不同,而有不同的表现形态(执行效果)。
    就像上面例子中的图形一样,自身是一个抽象类,其中存在一些抽象方法,具体的执行可以由子类对象来完成。对于抽象类的抽象方法,由于子类必须进行重写,所以由子类去执行父类的抽象方法必然是多态的体现,对于其他的情况则未必构成多态,因此总结了以下三个必要条件。

    2. 多态的必要条件

    • 存在子父类继承关系
    • 子类重写父类的方法
    • 父类引用指向子类对象

    只有满足了这三个条件才能构成多态,这也就是文章前三点用这么长的篇幅来铺垫的原因。

    3. 多态的优点

    使用多态有多种好处,特别是一个抽象类有多个子类,或一个接口存在多个抽象类时,在进行参数传递时就会非常的灵活,在方法中只需要定义一个父类型作为声明,传入的参数可以是父类型本身,也可以是对应的任意子类型对象。于是,多态的优点可以总结如下:

    • 降低耦合:只需要与父类型产生关联即可
    • 可维护性(继承保证):只需要添加或修改某一子类型即可,不会影响其他类
    • 可扩展性(多态保证):使用子类,可以对已有功能进行快速扩展
    • 灵活性
    • 接口性

    扫描下方二维码,加入官方粉丝微信群,可以与我直接交流,还有更多福利哦~

    在这里插入图片描述

    展开全文
  • 面向对象重要三个基本特征

    千次阅读 2016-03-08 23:01:41
    面向对象三个基本特征是:封装、继承、多态。
    
    

    面向对象的三个基本特征是:封装、继承、多态。


    封装

    封装,也就是把客观事物封装成抽象的类,并且类可以把自己的数据和方法只让可信的类或者对象操作,对不可信的进行信息隐藏。

    继承

    面向对象编程 (OOP) 语言的一个主要功能就是继承。继承是指这样一种能力:它可以使用现有类的所有功能,并在无需重新编写原来的类的情况下对这些功能进行扩展。

    通过继承创建的新类称为“子类”或“派生类”。

    被继承的类称为基类父类超类

    继承的过程,就是从一般到特殊的过程。

    要实现继承,可以通过继承Inheritance)和组合Composition)来实现。

    在某些 OOP 语言中,一个子类可以继承多个基类。但是一般情况下,一个子类只能有一个基类,要实现多重继承,可以通过多级继承来实现。


    继承概念的实现方式有三类:实现继承、接口继承和可视继承。

      实现继承是指使用基类的属性和方法而无需额外编码的能力;

     接口继承是指仅使用属性和方法的名称、但是子类必须提供实现的能力;

     可视继承是指子窗体(类)使用基窗体(类)的外观和实现代码的能力。

    在考虑使用继承时,有一点需要注意,那就是两个类之间的关系应该是属于关系。例如,Employee 是一个人,Manager 也是一个人,因此这两个类都可以继承 Person 类。但是Dog 类却不能继承 Person 类,因为狗并不是人。

    抽象类仅定义将由子类创建的一般属性和方法,创建抽象类时,请使用关键字 Interface 而不是 Class

    多态

    多态性(polymorphisn)是允许你将父对象设置成为和一个或更多的他的子对象相等的技术,赋值之后,父对象就可以根据当前赋值给它的子对象的特性以不同的方式运作。简单的说,就是一句话:允许将子类类型的指针赋值给父类类型的指针。

    实现多态,有二种方式,覆盖,重载。

    覆盖,是指子类重新定义父类的虚函数的做法。

    重载,是指允许存在多个同名函数,而这些函数的参数表不同(或许参数个数不同,或许参数类型不同,或许两者都不同)。

    其实,重载的概念并不属于面向对象编程,重载的实现是:编译器根据函数不同的参数表,对同名函数的名称做修饰,然后这些同名函数就成了不同的函数。对于这两个函数的调用,在编译器间就已经确定了,是静态的(记住:是静态)。也就是说,它们的地址在编译期就绑定了,因此,重载和多态无关!真正和多态相关的是覆盖。当子类重新定义了父类的虚函数后,父类指针根据赋给它的不同的子类指针,动态的调用属于子类的该函数,这样的函数调用在编译期间是无法确定的。因此,这样的函数地址是在运行期绑定的。结论就是:重载只是一种语言特性,与多态无关,与面向对象也无关!

    那么,多态的作用是什么呢?我们知道,封装可以隐藏实现细节,使得代码模块化;继承可以扩展已存在的代码模块(类);它们的目的都是为了——代码重用。而多态则是为了实现另一个目的——接口重用!多态的作用,就是为了类在继承和派生的时候,保证使用家谱中任一类的实例的某一属性时的正确调用。


    展开全文
  • 面向对象三个基本特征

    万次阅读 2018-09-05 17:11:31
    面向对象三个基本特征是:封装、继承、多态。 封装 封装最好理解了。封装是面向对象特征之一,是对象和类概念的主要特性。 封装,也就是把客观事物封装成抽象的类,并且类可以把自己的数据和方法只让可信的...
  • 面向对象编程及其大特性

    万次阅读 2019-06-11 11:39:23
    编程语言分为面向过程编程、函数式编程和面向对象编程。其实python就是一种面向对象编程,那么我们先了解一下它们的特点和优缺点以及它们的区别是什么。 面向过程编程:“面向过程”(Procedure Oriented)是一种以...
  • java-面向对象编程-大特性之封装

    千次阅读 2017-01-20 22:24:57
    我们在上一章中谈到了面向对象编程大特性之一的继承。并且说到在继承中,父类其实是从子类中抽象出来的,而在这里所说的抽象,就可以理解为数据封装的一种表达方式。而准确来说,所谓的封装,就是在人为对客观...
  • Java语言是纯粹的面向对象的程序设计语言,这主要表现为Java完全支持面向对象种基本特征:继承、封装和多态。Java语言完全以对象为中心,Java程序的最小程序单位是类,整个Java程序由一的类组成。 Java...
  • 面向对象编程三大特性------封装、继承、多态

    万次阅读 多人点赞 2016-06-07 11:41:12
    本文是对面向对象编程三大特性(封装、继承、多态)的一学习总结。 封装隐藏了类的内部实现机制,可以在不影响使用的情况下改变类的内部结构,同时也保护了数据。对外界而已它的内部细节是隐藏的,暴露给外界的...
  • 简述面向函数编程和面向对象编程的区别? 什么时候使用面向函数编程?什么时候使用面向对象编程? 函数式编程,顾名思义,这种编程是以函数思维做为核心,在这种思维的角度去思考问题。 这种编程最重要的基础是λ...
  • JavaScript 进阶教程(1)--面向对象编程

    万次阅读 多人点赞 2020-08-16 18:13:37
    1 学习目标 理解面向对象开发思想 掌握 JavaScript 面向对象开发相关模式 ...当实物被抽象成对象,实物之间的关系就变成了对象之间的关系,从而就可以模拟现实情况,针对对象进行编程。 (2) 对象是一.
  • 面向对象是为了解决系统的可维护性,可扩展性,可重用性。...1、计算机是帮助人们解决问题的,然而计算机终究是机器,他只会按照人所写的代码,一步一步的执行下去,最终得到了结果,因此无论程序多么的复杂
  • 关于面向对象以及特征的解释

    千次阅读 2018-05-14 22:32:30
    关于面向对象以及特征的解释面向对象: 在C语言编程中是面向过程而在Java编程中是面向对象的。面向过程更重要的是看重实现的具体过程,面向对象看重的是结果,不管其里面的具体过程,只看结果。 举一例子:...
  • 面向对象编程(Python版详解)

    千次阅读 多人点赞 2020-04-03 14:14:18
    面向对象编程介绍二.类和对象.类的构成 一.面向对象编程介绍 如今主流的软件开发思想有两种:一是面向过程,另一是面向对象。面向过程出现得较早,典型代表为C语言,开发中小型项目的效率很高,但是很难适用...
  • 面向对象编程思想

    千次阅读 2018-10-11 07:35:59
    Java面向对象编程思想Java对象什么是对象如何创建对象对象的生命周期继承什么是继承继承语法向上转型继承与初始化多态什么是多态产生正确的行为功能快捷键合理的创建标题,有助于目录的生成如何改变文本的样式插入...
  • 面向对象编程,这种编程是把问题看作由对象的属性与对象所进行的行为组成。基于对象的概念,以类作为对象的模板,把类和继承作为构造机制,以对象为中心,来思考并解决问题。 优点 函数式编程:支持闭包和高阶...
  • 文章目录前言面向对象:举最简单点的例子来区分 面向过程和面向对象:面向过程:面向对象的大特性:类和对象定义类创建和使用对象构造方法 【Python入门自学笔记专辑】——面向对象编程 前言 ​ 面相对象是...
  • 面向对象编程基本概念

    千次阅读 2018-04-18 15:41:53
    面向对象编程(OOP)为软件社区引入了一场革命,以帮助解决这些问题。 OOP专注于模块化,改变容忍度,代码重用,易于理解和分布式开发。今天大多数项目都使用面向对象的概念。由于C ++引入了OOP,因此用户体验已经...
  • 说实话,没有一定编程基础,这两还真的是很难懂,因为对于IT编程思想很重要,如果有了编程思想,这两的区别就很好理解了。 1、面向对象编程: 首先java就是面向对象编程,所谓在java中万事万物皆对象...
  • 然后聊起面向对象,虽然我们一直在用,但真的问起你什么叫面向对象时,还是很难有一具相的回答,因此本文尝试以OOP为中心,以讲解和对比的方式,聊聊这编程思想。 OOP前夕:POP 谈起了OOP,我们就不得不了解...
  • 面向对象编程与面向过程编程的区别(翻译版)  我们知道现在存在着两种不同的编程方式-1) 面向过程编程(POP)以及2)面向对象编程。我们可以任意选择一种方式来编写程序,但是我们得知道这两种编程方式的区别。这...
  • 其实目的还是为了跟上一些主流编程语言的脚步,例如 java 、C++ 、Python,他们内部都是用 class 语法来实现的面向对象编程,所以咱们的 JavaScript 也不能落后,不然很多学习过 java c++ python 的小伙伴跑来学习 ...
  • javascript面向对象编程技巧

    千次阅读 2011-08-09 07:11:51
    Javascript在HTML5到来...而随着Javascript 2.0规范的采用,Javascript越来越具有一门强大的编程语言所需的所有特性。在这其中,面向对象编程就是一个重要的方面。 面向对象有四大领域:抽象、封装、继承、多态。下面
  • Kotlin的面向对象编程,深入讨论继承写法的问题

    万次阅读 多人点赞 2019-05-20 08:55:57
    本来计划是准备直播大概一个半小时,最后直播了三个小时还没讲完,因此为了赶时间不得不砍掉了一些本来要讲的内容。 当时提到了一个Kotlin在继承时括号书写的问题,这部分内容比较有疑惑性,不太利于初学者理解。...
  • PLC的面向对象编程

    千次阅读 2018-04-24 23:27:16
    面向对象编程是计算机高级语言的一种先进的编程模式,在工业控制系统的PLC程序中也可以采用这种设计思想,虽然我们无法实现面向对象的很多优秀特点如“继 承”,甚至于它根本就不具备面向对象编程语言的特点,但面向...
  • 什么是面向对象编程(OOP)?

    千次阅读 2018-10-23 15:29:44
    Java 程序员第一要了解的基础概念就是:什么是面向对象编程(OOP)
  • 面向对象编程基础 活在当下的程序员应该都听过“面向对象编程”一词,也经常有人问能不能用一句话解释下什么是“面向对象编程”,我们先来看看比较正式的说法。 把一组数据结构和处理它们的方法组成对象(object...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 447,228
精华内容 178,891
关键字:

对象编程的三个重要特征