Java编程语言理解 - 面向对象的特征

面向对象的特征有哪些方面?

抽象:抽象是将一类对象的共同特征总结出来构造类的过程,包括数据抽象行为抽象两方面。抽象只关注对象有哪些属性和行为,并不关注这些行为的细节是什么。

继承:继承是从已有类得到继承信息创建新类的过程。提供继承信息的类被称为父类(超类、基类);得到继承信息的类被称为子类(派生类)。继承让变化中的软件系统有了一定的延续性,同时继承也是封装程序中可变因素的重要手段(如果不能理解请阅读阎宏博士的《Java与模式》或《设计模式精解》中关于桥梁模式的部分)。

封装:通常认为封装是把数据和操作数据的方法绑定起来,对数据的访问只能通过已定义的接口。面向对象的本质就是将现实世界描绘成一系列完全自治、封闭的对象。我们在类中编写的方法就是对实现细节的一种封装;我们编写一个类就是对数据和数据操作的封装。可以说,封装就是隐藏一切可隐藏的东西,只向外界提供最简单的编程接口(可以想想普通洗衣机和全自动洗衣机的差别,明显全自动洗衣机封装更好因此操作起来更简单;我们现在使用的智能手机也是封装得足够好的,因为几个按键就搞定了所有的事情)。

多态性:多态性是指允许不同子类型的对象对同一消息作出不同的响应。简单的说就是用同样的对象引用调用同样的方法但是做了不同的事情。多态性分为编译时的多态性和运行时的多态性。如果将对象的方法视为对象向外界提供的服务,那么运行时的多态性可以解释为:当A系统访问B系统提供的服务时,B系统有多种提供服务的方式,但一切对A系统来说都是透明的(就像电动剃须刀是A系统,它的供电系统是B系统,B系统可以使用电池供电或者用交流电,甚至还有可能是太阳能,A系统只会通过B类对象调用供电的方法,但并不知道供电系统的底层实现是什么。


方法重载(overload)实现的是编译时的多态性(也称为前绑定)

方法重写(override)实现

 的是运行时的多态性(也称为后绑定)

运行时的多态是面向对象最精髓的东西,要实现多态需要做两件事:

1).重写

2). 对象造型(用父类型引用的方法就会根据子类对象的不同而表现出不同的行为)。

封装的好处:

一个普通的类:
public class User{
     String  name;
     String  sex;
     int    age;
     public User(){
         //...
     }
}
//使用时:
User user  = new User();
 user.name="xxx";
 user.age = 20;
 user.sex="xx";

如何对其字段的数值进行限制-比如age不能大于200;---但开发中常常使用的是表单提交实现类属性的赋值,MVC可以通过视图层验证--但仍然可以通过某些方式跳过前端验证的手段因此会出现JSR303验证。

而且如果User类的内部的结构发生变化,如对一个属性的结构--类型做了变化那么用到此类的其他类都要做修改--岂不是很麻烦---

                                  如果使用get方法获取属性值,那么当其属性结构改变时一定能够通过某种方式来修改get方法的实现使其return的值不发生变化

此足以说明这样的写法不够灵活

一个封装的类
public class User{
     private String  name;
     private    String  sex;
     private    int    age;
     private     int  single;
     public User(){
         //...
     }
     public setName(String name){
         this.name = name;
     }
     public String getName(){
          return name;
    }
     //...其他属性get set方法
}

如何理解封装的隐藏一切可隐藏的东西,只向外界提供最简单的编程接口

private 关键字可以让其他类(对象)不能调用本类的属性,不可见|单如果一个类对其他类不可见的还要这样的一个类做什么?-->所以提供set和get方法来操作此类想要外部的类操作的属性(其实只是属性的一部分细节,因为并不能完全按调用者的本身去使用它,只能按照其类get set方法的实现机制去调用它)===>同样需要一写只能在本类使用的属性则不暴露给外部的类,实现隐藏

一个类对于自身的成员有绝对的控制权

其就像房子和窗户的关系-房子不能完全封闭,需要窗子来与外界交互--通过窗子可以了解房子的内部一些细节,但却不能看清全部-如果提供一扇门,并让观察者get到钥匙进入其中就可以...

可见这样设计更加自由和可自定义性

封装能够

       在不影响自身‘使用者’的情况下修改自己的内部结构

       很灵活的对自身的属性与交互性进行控制

       暴露自己应该暴露的细节-隐藏一切可隐藏信息

继承的好处:

      继承可以极大的实现代码的复用--继承的最常用的是向上转型--如果在不需要使用向上转型的结构里 尽量不要使用继承而使用组合,因为继承的一个弊端是子类对服类具有很强的依赖性(强耦合由此而来),而java项目结构设计时最关心的就是类与类之间少的依赖----但是这样的依赖又产生了什么坏处,导致这么摒弃继承?

一个暂时不确定性的弊端是父类的改变必然会引起子类的改变--(个人并没有案例来说明此带来的坏的影响)

      网上搜索继承的优缺点,一大堆,仔细筛选了仅没有看见一个能够让自己理解继承为什了会破坏封装的理由,  难道是自己的理解能力太差了?

      网上的理由都集中在一点上,就是子类继承父类后,那么父类的属性和实现细节对子类是透明的。

难道子类继承父类之后其对父类的访问权限有一定会比其他类调用其父类的权限高?父类的成员变量不想对子类开放的依旧可以是private的,其并不会有任何影响,对于想暴露给子类的细节(某个属性的get set方法)而不想暴露给其他非子类的细节同样可以使用protected实现

父类中封装好的对外界隐藏的东西,子类继承过来后当然也应该是对外界隐藏

子类仅仅是扩展了父类而并不会维护父类这样的设计怎么就破坏了封装!!!

继承的概念是:隐藏属性,方法或实现细节的过程,仅对外公开需要的接口

继承的概念是:在父类和子类之间存在着继承和扩展关系;子类继承父类的属性和方法的同时,子类还可以扩展出新的属性和方法,并且还可以覆盖父类中方法的实现方式

注意:private修饰的属性依然可以继承,只是子类无权访问罢了。。有疑问的朋友自行测试:先继承一个私有成员的类让后通过子类.的方式调用-记录抛出的异常-然后去掉继承,直接.记录抛出的异常比较即可

然后谈谈依赖的问题:如果其他类调用该类一样会产生依赖(依赖是值哪一个类的依赖的实现改变,自身也有一定的变化),子类调用父类产生的依赖程度难道就相对大的多?

网上的一些说法是:父类常常会定义一部分子类的表现特征,使得父类和子类之间的实现代码产生相互依赖.

这是什么情况,父类为什么要定义子类的一些表现特征--哪位朋友会这样设计产生这样不必要的耦合

还有一些说法:继承会失去灵活性

明确的使用具体类名将固定到特定的实现,给底层的改变增加了不必要的困难;???

这是为什么?难道对类的扩展性造成了什么影响,那如果把基类写成抽象类?抽象类就好比接口与继承的结合体,但是也需要继承

继承是支持重写的,所以需求变更同样可以重写不同的实现机制---继承同样支持泛型机制和上溯造型

继承的上塑造型不能直接调用子类的扩展的属性和方法==>调用子类重写的方法时,如果重写的方法中出现了子类新增的成员变量或常量 那么是没有问题的==>需要的时候同样可以下塑造型,可以直接调用子类扩展的属性和方法(如果没有尝试过的朋友,或有疑问的朋友请自行测试)

--接口的上塑造型和下塑造型也是一样的-接口比抽象类更加抽象,抽象到其只有行为的定义,行为的实现完全交给子类而子类也必须实现

一个类可以实现多个接口,但只能继承一个父类。如果像c一样可以多继承,那么整个结构会显得很复杂-难于理解。

接口的确比继承更具有灵活性-jdk1.8又为接口新增的default关键字修饰方法,也就是,如果发现了新的需求,而需要修改一个接口添加一个新的行为,不用让其子类都去实现此行为(要去修改所有的子类),仅需要用default修饰此行为并作出具体的实现--相当于默认的行为(方法)的实现--default关键字仅能修饰接口的方法

个人认为接口和继承并不是相互替代的,而是相互促进,各自实现自己各自的需求,适合不同的场景,能用接口也尽量用接口,不能说明继承比不上接口,只某种情况使用接口更合适--针对网上很多说接口是‘陷阱’,内容只是在阐述别人的观点,却不说明原因--非常恼火--至始至终我都觉得继承有时候是非常有用的,并不觉得有什么‘陷阱’;

java8里面也有许多继承实现的比较好的案例,比如:AbstractMap通过实现Map接口进行包装,然后HashMap等其他Map直接继承就可以对其进行扩展--试想一下如果没有AbstractMap的出现,Map下众多的实现类需要写多少重复的代码。

当然:相对于组合来说,继承的确会有一定的不足,在调用的子类的时候调用者需要关心子类的公共方法还需要去关心其父类的公共方法,如果存在多重继承那么理解起来有一定的难度,这也是避免多重继承的原因。需要上溯造型的时候需要选择继承

组合和继承一样可以实现代码的复用,且只产生了较小的依赖---组合可以选择性的复用,而继承则是复用全部,包括不需要的复用--但是设计基类的时候,设计者也不会设计一些子类不需要的东西来填充子类其实设计基类与设计接口有着同样的思想。

不过:Jams Gosling说过想要抛弃继承也一定有原因的,只是以自己的水平可能还不能理解,等以后接触更深的再补充


多态的好处:

 多态的主要的体现是上溯造型(向上转型)--主要的实现使通过接口实现,继承父类进行方法重写,同一个类中进行方法重载

 产生多态的条件:继承或实现 && 要有重写 &&父类引用指向子类的实例对象

        多态具有很好的扩展性:增加新的子类不会对现有的结构造成任何负面的影响,只会是整个系统的结构更加完美;

        引用的直接性,抽象性:多态是超类通过方法签名,向子类提供了一个共同接口,由子类来完善或者覆盖它而实现的.--在需要子类的地方,可以直接去找超类的,即使用超类的引用。。

       灵活性:如果在基类里添加新的非公共的需求需求(新的抽象方法):每一个子类不同的,子类必须实现的,那么使用继承来实现多态就会产生弊端,因为Class内部如果增加一个抽象的方法子类必须重写,那么修改基类就会导致子类都要全部修改,而接口就不用,因为在jdk1.8的时候为接口新增了一个default关键字,是的接口更加凸显优势。

        可替换性:可以增强结构的健壮性,只管按照父类的设计进行操作,不管具体是什么样的子类,将来这个子类用着不舒服了,换一个就行,不影响原来的代码,这样代码维护起来就更加容易

      多态的上溯造型只能调用超类定义的方法或属性

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

雨中漫步t2

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值