-
Java面向对象的三大特征(封装 继承 多态)
2021-01-14 10:36:17Java面向对象的三大特征(封装 继承 多态) 1.封装 在面向对象程式设计方法中,封装(英语:Encapsulation)是指一种将抽象性函式接口的实现细节部分包装、隐藏起来的方法。 封装可以被认为是一个保护屏障,防止该类...Java面向对象的三大特征(封装 继承 多态)
1.封装
在面向对象程式设计方法中,封装(英语:Encapsulation)是指一种将抽象性函式接口的实现细节部分包装、隐藏起来的方法。封装可以被认为是一个保护屏障,防止该类的代码和数据被外部类定义的代码随机访问。
要访问该类的代码和数据,必须通过严格的接口控制。
封装最主要的功能在于我们能修改自己的实现代码,而不用修改那些调用我们代码的程序片段。
适当的封装可以让程式码更容易理解与维护,也加强了安全性。
封装的优点:- 良好的封装能够减少耦合性。
- 类内部的结构可以随意修改
- 可以对成员变量进行更精确的控制。
- 隐藏信息,细节。
实现封装
-
修改属性的可见性来限制对属性的访问(一般限制为private),例如:
public class Person {
private String name;
private int age;
private String address;public String getName() {
return name;
}public void setName(String name) {
this.name = name;
}public int getAge() {
return age;
}public void setAge(int age) {
this.age = age;
}public String getAddress() {
return address;
}public void setAddress(String address) {
this.address = address;
}
这段代码中,将 name 和 age 属性设置为私有的,只能本类才能访问,其他类都访问不了,如此就对信息进行了隐藏。
实例
让我们来看一个java封装类的例子:public class Person { private String name; private int age; private String address; public String getName() { return name; } public void setName(String name) { this.name = name; } public int getAge() { return age; } public void setAge(int age) { this.age = age; } public String getAddress() { return address; } public void setAddress(String address) { this.address = address; }
以上实例中public方法是外部类访问该类成员变量的入口。
通常情况下,这些方法被称为getter和setter方法。
因此,任何要访问类中私有成员变量的类都要通过这些getter和setter方法。
通过如下的例子说明Person类的变量怎样被访问:
public class RunEncap{ public static void main(String args[]){ Person encap = new Person(); encap.setName("James"); encap.setAge(20); encap.setAddress("12343ms"); System.out.print("Name : " + encap.getName()+ " Age : "+ encap.getAge()); } }
运行结果:
Name : James Age : 20
2.继承
继承的概念
继承是java面向对象编程技术的一块基石,因为它允许创建分等级层次的类。继承就是子类继承父类的特征和行为,使得子类对象(实例)具有父类的实例域和方法,或子类从父类继承方法,使得子类具有父类相同的行为
继承格式
在 Java 中通过 extends 关键字可以申明一个类是从另外一个类继承而来的class 父类 { } class 子类 extends 父类 { }
继承类型
继承的特性
1.子类拥有父类非 private 的属性、方法。2.子类可以拥有自己的属性和方法,即子类可以对父类进行扩展。
子类可以用自己的方式实现父类的方法。
Java 的继承是单继承,但是可以多重继承,单继承就是一个子类只能继承一个父类,多重继承就是,例如 B 类继承 A 类,C 类继承 B 类,所以按照关系就是 B 类是 C 类的父类,A 类是 B 类的父类,这是 Java 继承区别于 C++ 继承的一个特性。
提高了类之间的耦合性(继承的缺点,耦合度高就会造成代码之间的联系越紧密,代码独立性越差)。
继承关键字
继承可以使用 extends 和 implements 这两个关键字来实现继承,而且所有的类都是继承于 java.lang.Object,当一个类没有继承的两个关键字,则默认继承object(这个类在 java.lang 包中,所以不需要 import)祖先类。extends关键字
在 Java 中,类的继承是单一继承,也就是说,一个子类只能拥有一个父类,所以 extends 只能继承一个类。implements关键字
使用 implements 关键字可以变相的使java具有多继承的特性,使用范围为类继承接口的情况,可以同时继承多个接口(接口跟接口之间采用逗号分隔)。super 与 this 关键字
super关键字:我们可以通过super关键字来实现对父类成员的访问,用来引用当前对象的父类。
this关键字:指向自己的引用。final关键字
final 关键字声明类可以把类定义为不能继承的,即最终类;或者用于修饰方法,该方法不能被子类重写:
多态
多态是同一个行为具有多个不同表现形式或形态的能力。多态就是同一个接口,使用不同的实例而执行不同操作,如图所示:
多态的优点- 消除类型之间的耦合关系
- 可替换性
- 可扩充性
- 接口性
- 灵活性
- 简化性
多态存在的三个必要条件
继承
重写
父类引用指向子类对象:Parent p = new Child();
重写
我们将介绍在 Java 中,当设计类时,被重写的方法的行为怎样影响多态性。我们已经讨论了方法的重写,也就是子类能够重写父类的方法。
当子类对象调用重写的方法时,调用的是子类的方法,而不是父类中被重写的方法。
要想调用父类中被重写的方法,则必须使用关键字 super。
多态的实现方式
方式一:重写:
这个内容已经在上一章节详细讲过,就不再阐述,详细可访问:Java 重写(Override)与重载(Overload)。
方式二:接口-
生活中的接口最具代表性的就是插座,例如一个三接头的插头都能接在三孔插座中,因为这个是每个国家都有各自规定的接口规则,有可能到国外就不行,那是因为国外自己定义的接口类型。
-
java中的接口类似于生活中的接口,就是一些方法特征的集合,但没有方法的实现。具体可以看 java接口 这一章节的内容。
方式三:抽象类和抽象方法
-
Java基础知识回顾之三 ----- 封装、继承和多态
2018-03-31 10:07:03在上一篇中回顾了java的修饰符和String类,这篇就来回顾下Java的三大特性:封装、继承、多态。 封装 什么是封装 在面向对象程式设计方法中,封装是指一种将抽象性函式接口的实现细节部份包装、隐藏起来的...前言
在上一篇中回顾了java的修饰符和String类,这篇就来回顾下Java的三大特性:封装、继承、多态。
封装
什么是封装
在面向对象程式设计方法中,封装是指一种将抽象性函式接口的实现细节部份包装、隐藏起来的方法。
封装可以被认为是一个保护屏障,防止该类的代码和数据被外部类定义的代码随机访问。要访问该类的代码和数据,必须通过严格的接口控制。
封装最主要的功能在于我们能修改自己的实现代码,而不用修改那些调用我们代码的程序片段。适当的封装可以让程式码更容易理解与维护,也加强了程式码的安全性。
简单的来说,就是将Java中的经常用到的代码进行封装起来,形成一个方法。比如,我们常用的实体类,使用private修饰变量,用于保护数据;对外提供getter和setter方法,用于调用。这就是一种典型的封装。
代码示例:
public class packagingTest { public static void main(String[] args) { User user=new User(); //这里会报错,因为id和name是私有的,用于保护该数据 // user.id=10; // user.name="张三"; user.setId(1); user.setName("张三"); System.out.println(user.getId()); System.out.println(user.getName()); } } class User{ private int id; private String name; public int getId() { return id; } public void setId(int id) { this.id = id; } public String getName() { return name; } public void setName(String name) { this.name = name; } }
运行结果:
1 张三
使用封装的好处
良好的封装能够减少耦合。
类内部的结构可以自由修改。
可以对成员变量进行更精确的控制。
隐藏信息,实现细节。
继承
什么是继承
继承是java面向对象编程技术的一块基石,因为它允许创建分等级层次的类。
继承就是子类继承父类的特征和行为,使得子类对象(实例)具有父类的实例域和方法,或子类从父类继承方法,使得子类具有父类相同的行为。继承的特性
- 子类拥有父类非private的属性,方法。
- 子类可以拥有自己的属性和方法,即子类可以对父类进行扩展。
- 子类可以用自己的方式实现父类的方法。
为什么使用继承
继承主要目的是为了复用代码!简单的来说,就是将重复的代码抽出来,放到父类中,然后在再由子类继承使用,子类也是可以对父类进行扩展的。所以在继承关系中,可以这么理解,父类更通用,子类更具体。
打个比方,在动物世界中,猫和狮子是属于猫科,狗和狼是属于犬科。而它们也都是动物。猫和狮子有个共同的父类猫科,猫和狗有个共同的父类动物。所以它们是符合继承关系的, 只不过它们在行为上有所区别。猫和狗都有吃和睡,不过猫可以爬树,狗不可以。
这里,我们可以使用如下代码来进行说明。代码示例:
public class extendTest { public static void main(String[] args) { Cat cat=new Cat(); Dog dog=new Dog(); cat.eat(); cat.sleep("cat"); cat.climbTree(); dog.eat("dog"); dog.sleep("dog"); } } class Animal{ public void eat(String name){ System.out.println(name+"正在吃东西..."); } public void sleep(String name){ System.out.println(name+"正在睡觉..."); } } class Cat extends Animal{ private String name="Cat"; public void eat(){ super.eat(name); System.out.println(name+"吃完了"); } public void sleep(){ this.sleep(name); } public void sleep(String name){ System.out.println(name+"刚刚睡觉!"); } public void climbTree(){ System.out.println(name+"正在爬树!"); } } class Dog extends Animal{ }
运行结果:
Cat正在吃东西... Cat吃完了 cat刚刚睡觉! Cat正在爬树! dog正在吃东西... dog正在睡觉...
在上述代码中,父类Animal实现了eat和sleep的方法,子类Cat和Dog使用了extends 关键字继承了父类Animal。子类Dog继承父类Animal之后什么都没做,而子类Cat不但继承了父类Animal,而且还增加了climbTree 方法,并且也重写了父类的eat和sleep方法。
在子类Cat中,出现了两个关键字:super和this。
这两个关键字的意义如下:- super关键字:实现对父类成员的访问,用来引用当前对象的父类。
- this关键字:指向自己的引用。
在上述代码中,子类Cat使用super关键字调用了父类Animal的eat方法,使用this关键字调用本类中的sleep方法。
说到继承,就不得不提这几个东西: final和protected修饰符、构造器、以及向上转型!
其中final和protected修饰符在上一篇java的修饰符和String类中已经讲解了,这里就简单的描述下。- final:修饰的类不可以被继承。
- protected:修饰的类仅对同一包内的类和所有子类可见。
构造器
虽然子类可以继承父类的属性和方法(private修饰的除外),但是还有一样是子类无法继承的,那就是是构造器!对于构造器而言,它只能够被调用,而不能被继承。如果子类想使用父类的构造器,那么只需使用super关键字调用即可。
注:如果父类的构造器被private所修饰,那么是无法被外部调用的,包括子类!
向上转型
将子类转换成父类,在继承关系上面是向上移动的,所以一般称之为向上转型。
之前的个例子中,猫和动物是属于继承关系,那么我们可以把猫当作动物就是向上转型!
例如:public class extendTest { public static void main(String[] args) { Animal animal=new Cat(); animal.eat("cat"); animal.sleep("cat"); } } class Animal{ public void eat(String name){ System.out.println(name+"正在吃东西..."); } public void sleep(String name){ System.out.println(name+"正在睡觉..."); } } class Cat extends Animal{ private String name="Cat"; public void eat(){ super.eat(name); System.out.println(name+"吃完了"); } public void sleep(){ this.sleep(name); } public void sleep(String name){ System.out.println(name+"刚刚睡觉!"); } public void climbTree(){ System.out.println(name+"正在爬树!"); } }
运行结果:
cat正在吃东西... cat刚刚睡觉!
上述代码中完成了向上转型,但是在向上转型中是存在着一些缺憾的,那就是属性和方法的丢失。例如上述代码中就丢失了Cat类中的climbTree()方法和name属性。所以慎用向上转型!
多重继承
Java的继承是单继承,但是可以实现多重继承!
虽然一个子类只能继承一个父类,但是子类的子类也可以子类。
例如C类继承B类,B类继承A类,所以按照关系就是A类是B类的父类,B类是C类的父类。继承的缺点
虽然继承大大提升了代码的复用性,但是也提高了类之间的耦合性!父类更改,子类就必须更改!因此可以说继承破坏了封装,因为对于父类而言,它的实现细节对与子类来说都是透明的。
所以慎用继承!!!多态
什么是多态
多态是指事物在运行过程中存在不同的状态。
多态就是指程序中定义的引用变量所指向的具体类型和通过该引用变量发出的方法调用在编程时并不确定,而是在程序运行期间才确定。
使用多态的必要条件
多态存在的三个必要条件:
- 要有继承关系;
- 子类要重写父类的方法;
- 父类引用指向子类对象,也就是向上转型。
多态使用的简单示例
在上面的继承讲解中,我们用到了猫和动物这两个之间的关系,这里我们也可以使用这,只需要稍微改下代码,就可以实现多态。
代码示例:
public class Test { public static void main(String[] args) { Animal animal=new Cat(); animal.eat(); } } class Animal{ private String name="Animal"; public void eat(){ System.out.println(name+"正在吃东西..."); sleep(); } public void sleep(){ System.out.println(name+"正在睡觉..."); } } class Cat extends Animal{ private String name="Cat"; public void eat(String name){ System.out.println(name+"吃完了"); sleep(); } public void sleep(){ System.out.println(name+"正在睡觉"); } }
输出结果:
Animal正在吃东西... Cat正在睡觉
看到了运行结果之后,如果不熟悉多态的话,是不是感觉有些奇怪呢?
打印的第一句应该好理解,为什么打印的第二句不是Animal的方法,而是Cat中的方法呢?我们知道多态是指事物在运行过程中存在不同的状态。而这里,我们用到了继承、重写以及向上转型。
在这里顺便提一下:在向上转型中,一个父类的引用是可以指向多种子类对象,那么在运行时对于同一个消息是由实际的被引用的对象的类型来决定。
根据上述这段理解,我们再来看刚刚的那个示例。
在Cat类中,重写了父类Animal的sleep方法,并重载了eat方法。重载之后的eat(String name)方法和父类Animal的eat()方法不是同一个方法,因为是会在向上转型丢失的。而Cat子类重写了sleep方法,因此在向上转型的时候是不会丢失的,并且因为指定对对象的引用类型是Cat,所以Animal在调用eat()方法的时候,先是调用本类中eat()方法,然后在调用子类中的sleep()方法!结论:
当父类引用指向子类方法时,必须调用那些父类中存在的方法,如果子类中对该方法进行了重写,那么在运行时就会动态调用子类中的方法,这就是多态。
使用多态的优点
摘自:https://www.cnblogs.com/jack204/archive/2012/10/29/2745150.html
- 可替换性(substitutability)。多态对已存在代码具有可替换性。例如,多态对圆Circle类工作,对其他任何圆形几何体,如圆环,也同样工作。
- 可扩充性(extensibility)。多态对代码具有可扩充性。增加新的子类不影响已存在类的多态性、继承性,以及其他特性的运行和操作。实际上新加子类更容易获得多态功能。例如,在实现了圆锥、半圆锥以及半球体的多态基础上,很容易增添球体类的多态性。
- 接口性(interface-ability)。多态是超类通过方法签名,向子类提供了一个共同接口,由子类来完善或者覆盖它而实现的。
- 灵活性(flexibility)。它在应用中体现了灵活多样的操作,提高了使用效率。
- 简化性(simplicity)。多态简化对应用软件的代码编写和修改过程,尤其在处理大量对象的运算和操作时,这个特点尤为突出和重要。
在对多态有一定的认识之后,可以尝试看看如下代码。
这是一个经典的多态问题,摘自:
http://blog.csdn.net/thinkGhoster/archive/2008/04/19/2307001.aspx代码示例:
public class extendsTest { public static void main(String[] args) { A a1 = new A(); A a2 = new B(); B b = new B(); C c = new C(); D d = new D(); System.out.println("1--" + a1.show(b)); System.out.println("2--" + a1.show(c)); System.out.println("3--" + a1.show(d)); System.out.println("4--" + a2.show(b)); System.out.println("5--" + a2.show(c)); System.out.println("6--" + a2.show(d)); System.out.println("7--" + b.show(b)); System.out.println("8--" + b.show(c)); System.out.println("9--" + b.show(d)); } } class A { public String show(D obj) { return ("A and D"); } public String show(A obj) { return ("A and A"); } } class B extends A{ public String show(B obj){ return ("B and B"); } public String show(A obj){ return ("B and A"); } } class C extends B{ } class D extends B{ }
运行结果:
1--A and A 2--A and A 3--A and D 4--B and A 5--B and A 6--A and D 7--B and B 8--B and B 9--A and D
分析
①②③比较好理解,一般不会出错。④⑤就有点糊涂了,为什么输出的不是”B and B”呢?!!先来回顾一下多态性。
运行时多态性是面向对象程序设计代码重用的一个最强大机制,动态性的概念也可以被说成“一个接口,多个方法”。Java实现运行时多态性的基础是动态方法调度,它是一种在运行时而不是在编译期调用重载方法的机制。
方法的重写Overriding和重载Overloading是Java多态性的不同表现。
重写Overriding是父类与子类之间多态性的一种表现,重载Overloading是一个类中多态性的一种表现。如果在子类中定义某方法与其父类有相同的名称和参数,我们说该方法被重写(Overriding)。子类的对象使用这个方法时,将调用子类中的定义,对它而言,父类中的定义如同被“屏蔽”了。如果在一个类中定义了多个同名的方法,它们或有不同的参数个数或有不同的参数类型,则称为方法的重载(Overloading)。Overloaded的方法是可以改变返回值的类型。
当超类对象引用变量引用子类对象时,被引用对象的类型而不是引用变量的类型决定了调用谁的成员方法,但是这个被调用的方法必须是在超类中定义过的,也就是说被子类覆盖的方法。(但是如果强制把超类转换成子类的话,就可以调用子类中新添加而超类没有的方法了。)
好了,先温习到这里,言归正传!实际上这里涉及方法调用的优先问题 ,优先级由高到低依次为:this.show(O)、super.show(O)、this.show((super)O)、super.show((super)O)。让我们来看看它是怎么工作的。
比如④,a2.show(b),a2是一个引用变量,类型为A,则this为a2,b是B的一个实例,于是它到类A里面找show(B obj)方法,没有找到,于是到A的super(超类)找,而A没有超类,因此转到第三优先级this.show((super)O),this仍然是a2,这里O为B,(super)O即(super)B即A,因此它到类A里面找show(A obj)的方法,类A有这个方法,但是由于a2引用的是类B的一个对象,B覆盖了A的show(A obj)方法,因此最终锁定到类B的show(Aobj),输出为”B and A”。
再比如⑧,b.show(c),b是一个引用变量,类型为B,则this为b,c是C的一个实例,于是它到类B找show(C obj)方法,没有找到,转而到B的超类A里面找,A里面也没有,因此也转到第三优先级this.show((super)O),this为b,O为C,(super)O即(super)C即B,因此它到B里面找show(Bobj)方法,找到了,由于b引用的是类B的一个对象,因此直接锁定到类B的show(B obj),输出为”B and B”。
按照上面的方法,可以正确得到其他的结果。
问题还要继续,现在我们再来看上面的分析过程是怎么体现出蓝色字体那句话的内涵的。它说:当超类对象引用变量引用子类对象时,被引用对象的类型而不是引用变量的类型决定了调用谁的成员方法,但是这个被调用的方法必须是在超类中定义过的,也就是说被子类覆盖的方法。还是拿a2.show(b)来说吧。a2是一个引用变量,类型为A,它引用的是B的一个对象,因此这句话的意思是由B来决定调用的是哪个方法。因此应该调用B的show(B obj)从而输出”B and B”才对。但是为什么跟前面的分析得到的结果不相符呢?!问题在于我们不要忽略了蓝色字体的后半部分,那里特别指明:这个被调用的方法必须是在超类中定义过的,也就是被子类覆盖的方法。
B里面的show(B obj)在超类A中有定义吗?没有!那就更谈不上被覆盖了。实际上这句话隐藏了一条信息:它仍然是按照方法调用的优先级来确定的。它在类A中找到了show(Aobj),如果子类B没有覆盖show(A obj)方法,那么它就调用A的show(Aobj)(由于B继承A,虽然没有覆盖这个方法,但从超类A那里继承了这个方法,从某种意义上说,还是由B确定调用的方法,只是方法是在A中实现而已);现在子类B覆盖了show(A obj),因此它最终锁定到B的show(A obj)。这就是那句话的意义所在。
其它
参考:
http://blog.csdn.net/thinkGhoster/archive/2008/04/19/2307001.aspx
https://www.cnblogs.com/jack204/archive/2012/10/29/2745150.html
https://blog.csdn.net/chenssy/article/details/12786385到此,本文就结束了,谢谢阅读!欢迎留言和点赞,你的支持是我写作最大的动力!
版权声明:
作者:虚无境
博客园出处:http://www.cnblogs.com/xuwujing
CSDN出处:http://blog.csdn.net/qazwsxpcm
个人博客出处:http://www.panchengming.com -
java 过度封装_Java基础知识回顾之三 ----- 封装、继承和多态
2021-02-28 17:15:39前言在上一篇中回顾了java的修饰符和String类,这篇就来回顾下Java的三大特性:封装、继承、多态。封装什么是封装在面向对象程式设计方法中,封装是指一种将抽象性函式接口的实现细节部份包装、隐藏起来的方法。封装...前言
在上一篇中回顾了java的修饰符和String类,这篇就来回顾下Java的三大特性:封装、继承、多态。
封装
什么是封装
在面向对象程式设计方法中,封装是指一种将抽象性函式接口的实现细节部份包装、隐藏起来的方法。
封装可以被认为是一个保护屏障,防止该类的代码和数据被外部类定义的代码随机访问。要访问该类的代码和数据,必须通过严格的接口控制。
封装最主要的功能在于我们能修改自己的实现代码,而不用修改那些调用我们代码的程序片段。适当的封装可以让程式码更容易理解与维护,也加强了程式码的安全性。
简单的来说,就是将Java中的经常用到的代码进行封装起来,形成一个方法。比如,我们常用的实体类,使用private修饰变量,用于保护数据;对外提供getter和setter方法,用于调用。这就是一种典型的封装。
代码示例:
public class packagingTest {
public static void main(String[] args) {
User user=new User();
//这里会报错,因为id和name是私有的,用于保护该数据
//user.id=10;
//user.name="张三";
user.setId(1);
user.setName("张三");
System.out.println(user.getId());
System.out.println(user.getName());
}
}
class User{
private int id;
private String name;
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
运行结果:
1
张三
使用封装的好处
良好的封装能够减少耦合。
类内部的结构可以自由修改。
可以对成员变量进行更精确的控制。
隐藏信息,实现细节。
继承
什么是继承
继承是java面向对象编程技术的一块基石,因为它允许创建分等级层次的类。
继承就是子类继承父类的特征和行为,使得子类对象(实例)具有父类的实例域和方法,或子类从父类继承方法,使得子类具有父类相同的行为。
继承的特性
子类拥有父类非private的属性,方法。
子类可以拥有自己的属性和方法,即子类可以对父类进行扩展。
子类可以用自己的方式实现父类的方法。
为什么使用继承
继承主要目的是为了复用代码!简单的来说,就是将重复的代码抽出来,放到父类中,然后在再由子类继承使用,子类也是可以对父类进行扩展的。所以在继承关系中,可以这么理解,父类更通用,子类更具体。
打个比方,在动物世界中,猫和狮子是属于猫科,狗和狼是属于犬科。而它们也都是动物。猫和狮子有个共同的父类猫科,猫和狗有个共同的父类动物。所以它们是符合继承关系的, 只不过它们在行为上有所区别。猫和狗都有吃和睡,不过猫可以爬树,狗不可以。
这里,我们可以使用如下代码来进行说明。
代码示例:
public class extendTest {
public static void main(String[] args) {
Cat cat=new Cat();
Dog dog=new Dog();
cat.eat();
cat.sleep("cat");
cat.climbTree();
dog.eat("dog");
dog.sleep("dog");
}
}
class Animal{
public void eat(String name){
System.out.println(name+"正在吃东西...");
}
public void sleep(String name){
System.out.println(name+"正在睡觉...");
}
}
class Cat extends Animal{
private String name="Cat";
public void eat(){
super.eat(name);
System.out.println(name+"吃完了");
}
public void sleep(){
this.sleep(name);
}
public void sleep(String name){
System.out.println(name+"刚刚睡觉!");
}
public void climbTree(){
System.out.println(name+"正在爬树!");
}
}
class Dog extends Animal{
}
运行结果:
Cat正在吃东西...
Cat吃完了
cat刚刚睡觉!
Cat正在爬树!
dog正在吃东西...
dog正在睡觉...
在上述代码中,父类Animal实现了eat和sleep的方法,子类Cat和Dog使用了extends 关键字继承了父类Animal。子类Dog继承父类Animal之后什么都没做,而子类Cat不但继承了父类Animal,而且还增加了climbTree 方法,并且也重写了父类的eat和sleep方法。
在子类Cat中,出现了两个关键字:super和this。
这两个关键字的意义如下:
super关键字:实现对父类成员的访问,用来引用当前对象的父类。
this关键字:指向自己的引用。
在上述代码中,子类Cat使用super关键字调用了父类Animal的eat方法,使用this关键字调用本类中的sleep方法。
说到继承,就不得不提这几个东西: final和protected修饰符、构造器、以及向上转型!
其中final和protected修饰符在上一篇java的修饰符和String类中已经讲解了,这里就简单的描述下。
final:修饰的类不可以被继承。
protected:修饰的类仅对同一包内的类和所有子类可见。
构造器
虽然子类可以继承父类的属性和方法(private修饰的除外),但是还有一样是子类无法继承的,那就是是构造器!对于构造器而言,它只能够被调用,而不能被继承。如果子类想使用父类的构造器,那么只需使用super关键字调用即可。
注:如果父类的构造器被private所修饰,那么是无法被外部调用的,包括子类!
向上转型
将子类转换成父类,在继承关系上面是向上移动的,所以一般称之为向上转型。
之前的个例子中,猫和动物是属于继承关系,那么我们可以把猫当作动物就是向上转型!
例如:
public class extendTest {
public static void main(String[] args) {
Animal animal=new Cat();
animal.eat("cat");
animal.sleep("cat");
}
}
class Animal{
public void eat(String name){
System.out.println(name+"正在吃东西...");
}
public void sleep(String name){
System.out.println(name+"正在睡觉...");
}
}
class Cat extends Animal{
private String name="Cat";
public void eat(){
super.eat(name);
System.out.println(name+"吃完了");
}
public void sleep(){
this.sleep(name);
}
public void sleep(String name){
System.out.println(name+"刚刚睡觉!");
}
public void climbTree(){
System.out.println(name+"正在爬树!");
}
}
运行结果:
cat正在吃东西...
cat刚刚睡觉!
上述代码中完成了向上转型,但是在向上转型中是存在着一些缺憾的,那就是属性和方法的丢失。例如上述代码中就丢失了Cat类中的climbTree()方法和name属性。所以慎用向上转型!
多重继承
Java的继承是单继承,但是可以实现多重继承!
虽然一个子类只能继承一个父类,但是子类的子类也可以子类。
例如C类继承B类,B类继承A类,所以按照关系就是A类是B类的父类,B类是C类的父类。
继承的缺点
虽然继承大大提升了代码的复用性,但是也提高了类之间的耦合性!父类更改,子类就必须更改!因此可以说继承破坏了封装,因为对于父类而言,它的实现细节对与子类来说都是透明的。
所以慎用继承!!!
多态
什么是多态
多态是指事物在运行过程中存在不同的状态。
多态就是指程序中定义的引用变量所指向的具体类型和通过该引用变量发出的方法调用在编程时并不确定,而是在程序运行期间才确定。
使用多态的必要条件
多态存在的三个必要条件:
要有继承关系;
子类要重写父类的方法;
父类引用指向子类对象,也就是向上转型。
多态使用的简单示例
在上面的继承讲解中,我们用到了猫和动物这两个之间的关系,这里我们也可以使用这,只需要稍微改下代码,就可以实现多态。
代码示例:
public class Test {
public static void main(String[] args) {
Animal animal=new Cat();
animal.eat();
}
}
class Animal{
private String name="Animal";
public void eat(){
System.out.println(name+"正在吃东西...");
sleep();
}
public void sleep(){
System.out.println(name+"正在睡觉...");
}
}
class Cat extends Animal{
private String name="Cat";
public void eat(String name){
System.out.println(name+"吃完了");
sleep();
}
public void sleep(){
System.out.println(name+"正在睡觉");
}
}
输出结果:
Animal正在吃东西...
Cat正在睡觉
看到了运行结果之后,如果不熟悉多态的话,是不是感觉有些奇怪呢?
打印的第一句应该好理解,为什么打印的第二句不是Animal的方法,而是Cat中的方法呢?
我们知道多态是指事物在运行过程中存在不同的状态。而这里,我们用到了继承、重写以及向上转型。
在这里顺便提一下:
在向上转型中,一个父类的引用是可以指向多种子类对象,那么在运行时对于同一个消息是由实际的被引用的对象的类型来决定。
根据上述这段理解,我们再来看刚刚的那个示例。
在Cat类中,重写了父类Animal的sleep方法,并重载了eat方法。重载之后的eat(String name)方法和父类Animal的eat()方法不是同一个方法,因为是会在向上转型丢失的。而Cat子类重写了sleep方法,因此在向上转型的时候是不会丢失的,并且因为指定对对象的引用类型是Cat,所以Animal在调用eat()方法的时候,先是调用本类中eat()方法,然后在调用子类中的sleep()方法!
结论:
当父类引用指向子类方法时,必须调用那些父类中存在的方法,如果子类中对该方法进行了重写,那么在运行时就会动态调用子类中的方法,这就是多态。
使用多态的优点
可替换性(substitutability)。多态对已存在代码具有可替换性。例如,多态对圆Circle类工作,对其他任何圆形几何体,如圆环,也同样工作。
可扩充性(extensibility)。多态对代码具有可扩充性。增加新的子类不影响已存在类的多态性、继承性,以及其他特性的运行和操作。实际上新加子类更容易获得多态功能。例如,在实现了圆锥、半圆锥以及半球体的多态基础上,很容易增添球体类的多态性。
接口性(interface-ability)。多态是超类通过方法签名,向子类提供了一个共同接口,由子类来完善或者覆盖它而实现的。
灵活性(flexibility)。它在应用中体现了灵活多样的操作,提高了使用效率。
简化性(simplicity)。多态简化对应用软件的代码编写和修改过程,尤其在处理大量对象的运算和操作时,这个特点尤为突出和重要。
代码示例:
public class extendsTest {
public static void main(String[] args) {
A a1 = new A();
A a2 = new B();
B b = new B();
C c = new C();
D d = new D();
System.out.println("1--" + a1.show(b));
System.out.println("2--" + a1.show(c));
System.out.println("3--" + a1.show(d));
System.out.println("4--" + a2.show(b));
System.out.println("5--" + a2.show(c));
System.out.println("6--" + a2.show(d));
System.out.println("7--" + b.show(b));
System.out.println("8--" + b.show(c));
System.out.println("9--" + b.show(d));
}
}
class A {
public String show(D obj) {
return ("A and D");
}
public String show(A obj) {
return ("A and A");
}
}
class B extends A{
public String show(B obj){
return ("B and B");
}
public String show(A obj){
return ("B and A");
}
}
class C extends B{
}
class D extends B{
}
运行结果:
1--A and A
2--A and A
3--A and D
4--B and A
5--B and A
6--A and D
7--B and B
8--B and B
9--A and D
分析
①②③比较好理解,一般不会出错。④⑤就有点糊涂了,为什么输出的不是"B and B”呢?!!先来回顾一下多态性。
运行时多态性是面向对象程序设计代码重用的一个最强大机制,动态性的概念也可以被说成“一个接口,多个方法”。Java实现运行时多态性的基础是动态方法调度,它是一种在运行时而不是在编译期调用重载方法的机制。
方法的重写Overriding和重载Overloading是Java多态性的不同表现。
重写Overriding是父类与子类之间多态性的一种表现,重载Overloading是一个类中多态性的一种表现。如果在子类中定义某方法与其父类有相同的名称和参数,我们说该方法被重写(Overriding)。子类的对象使用这个方法时,将调用子类中的定义,对它而言,父类中的定义如同被“屏蔽”了。如果在一个类中定义了多个同名的方法,它们或有不同的参数个数或有不同的参数类型,则称为方法的重载(Overloading)。Overloaded的方法是可以改变返回值的类型。
当超类对象引用变量引用子类对象时,被引用对象的类型而不是引用变量的类型决定了调用谁的成员方法,但是这个被调用的方法必须是在超类中定义过的,也就是说被子类覆盖的方法。(但是如果强制把超类转换成子类的话,就可以调用子类中新添加而超类没有的方法了。)
好了,先温习到这里,言归正传!实际上这里涉及方法调用的优先问题 ,优先级由高到低依次为:this.show(O)、super.show(O)、this.show((super)O)、super.show((super)O)。让我们来看看它是怎么工作的。
比如④,a2.show(b),a2是一个引用变量,类型为A,则this为a2,b是B的一个实例,于是它到类A里面找show(B obj)方法,没有找到,于是到A的super(超类)找,而A没有超类,因此转到第三优先级this.show((super)O),this仍然是a2,这里O为B,(super)O即(super)B即A,因此它到类A里面找show(A obj)的方法,类A有这个方法,但是由于a2引用的是类B的一个对象,B覆盖了A的show(A obj)方法,因此最终锁定到类B的show(Aobj),输出为"B and A”。
再比如⑧,b.show(c),b是一个引用变量,类型为B,则this为b,c是C的一个实例,于是它到类B找show(C obj)方法,没有找到,转而到B的超类A里面找,A里面也没有,因此也转到第三优先级this.show((super)O),this为b,O为C,(super)O即(super)C即B,因此它到B里面找show(Bobj)方法,找到了,由于b引用的是类B的一个对象,因此直接锁定到类B的show(B obj),输出为"B and B”。
按照上面的方法,可以正确得到其他的结果。
问题还要继续,现在我们再来看上面的分析过程是怎么体现出蓝色字体那句话的内涵的。它说:当超类对象引用变量引用子类对象时,被引用对象的类型而不是引用变量的类型决定了调用谁的成员方法,但是这个被调用的方法必须是在超类中定义过的,也就是说被子类覆盖的方法。还是拿a2.show(b)来说吧。
a2是一个引用变量,类型为A,它引用的是B的一个对象,因此这句话的意思是由B来决定调用的是哪个方法。因此应该调用B的show(B obj)从而输出"B and B”才对。但是为什么跟前面的分析得到的结果不相符呢?!问题在于我们不要忽略了蓝色字体的后半部分,那里特别指明:这个被调用的方法必须是在超类中定义过的,也就是被子类覆盖的方法。
B里面的show(B obj)在超类A中有定义吗?没有!那就更谈不上被覆盖了。实际上这句话隐藏了一条信息:它仍然是按照方法调用的优先级来确定的。它在类A中找到了show(Aobj),如果子类B没有覆盖show(A obj)方法,那么它就调用A的show(Aobj)(由于B继承A,虽然没有覆盖这个方法,但从超类A那里继承了这个方法,从某种意义上说,还是由B确定调用的方法,只是方法是在A中实现而已);现在子类B覆盖了show(A obj),因此它最终锁定到B的show(A obj)。这就是那句话的意义所在。
其它
-
Java面向对象的三个特征:封装、继承、多态
2018-06-11 23:18:14封装的意义在于保护或者防止代码被意外修改。 封装提供了一个有效的途径来保护数据不被意外的破坏。将数据的作用域在程序中定义为public改为private在很多方面会更好。私有的数据可以用两种方式来间接的控制。第一...一、封装
定义
封装就是将数据或函数等集合在一个个的单元中,通俗来讲就是将属性或方法定义在一个类中
意义
封装的意义在于保护或者防止代码被意外修改。
封装提供了一个有效的途径来保护数据不被意外的破坏。将数据的作用域在程序中定义为public改为private在很多方面会更好。私有的数据可以用两种方式来间接的控制。第一种方法,我们使用传统的存、取方法。第二种方法我们用属性(property)。
封装时的权限控制符区别如下:
作用域使用原则:尽量使用private例
/** * 封装 */ public class Animal { //私有化属性 private String name; //私有化方法 private void eat(){ } }
二、继承
继承主要实现重用代码,节省开发时间。继承通过extends关键字来实现
例
/** * 继承 */ public abstract class Animal { public abstract void eat(); } public class Dog extends Animal { @Override public void eat() { } }
三、多态
定义
同一操作作用于不同的对象,可以有不同的解释,产生不同的执行结果。
多态的三个条件:
继承、重写、父类引用指向子类对象当使用多态方式调用方法时,首先检查父类中是否有该方法,如果没有,则编译错误;如果有,再去调用子类的同名方法。
多态的好处:可以使程序有良好的扩展,并可以对所有类的对象进行通用处理。
多态的实现方式:重写、接口、抽象类和抽象方法
例
public class Person { private void eat(){ System.out.println("人吃饭!"); } } public class Chinese extends Person{ // 重写父类方法 public void eat() { System.out.println("中国人在吃饭!"); } } public class English extends Person{ // 重写父类方法 public void eat() { System.out.println("英国人在吃饭!"); } } // 测试类 public class TestEat { public static void main(String[] args) { TestEat test = new TestEat(); // 引用指向中国人,创建中国人类对象 Person person1 = new Chinese(); // 此时调用的是Chinese的eat()方法 test.showEat(person1); Person person2 = new English(); // 此时调用的是English的eat()方法 test.showEat(person2); } // 使用父类作为方法的形参,实现多态 public void showEat(Person person) { // 传入的是哪具对象就调用哪个对象的eat()方法 person.eat(); } }
-
java三大 优点_JAVA的三大特性
2021-03-22 16:01:56JAVA的三大特性:封装,继承,多态。封装1.定义:在面向对象程式设计方法中,封装(英语:Encapsulation)是指一种将抽象性函式接口的实现细节部份包装、隐藏起来的方法。封装可以被认为是一个保护屏障,防止该类的... -
java 三大特性_java的三大特性是什么?
2021-02-27 08:14:20java的三大特性Java语言的三大特性即是:封装、继承、多态首先先简单的说一下其3大特性的定义:封装:在面向对象程式设计方法中,封装(英语:Encapsulation)是指一种将抽象性函式接口的实现细节部分包装、隐藏起来的... -
Java 三大特性——封装、继承、多态
2016-03-23 14:25:00概念:在面向对象程式设计方法中,封装(英语:Encapsulation)是指,一种将抽象性函式接口的实作细节部份包装、隐藏起来的方法,可以被认为是一个保护屏障,防止该类的代码和数据被外部类定义的代码随机访问,要访问... -
java基础特性,封装,继承,多态
2021-04-02 19:43:10封装可以被认为是一个保护屏障,防止该类的代码和数据被外部类定义的代码随机访问。 隐藏对象的属性和实现细节,仅对外公开接口,控制在程序中属性的读和修改的访问级别。将抽象得到的数据和行为(或功能)相结合,... -
面向对象编程的三大特性在JAVA中的体现
2018-06-24 21:46:50封装就是private public 一般属性是private主要是防止别的类直接访问这个属性对应的setter和getter方法是public,提供对该属性的获取和修改继承:从一个类派生出一个新的类,派生出的类称为子类(派生类),被派生的... -
中继承父类实现父类方法的快捷键_封装,多态,继承
2021-01-12 08:01:37封装性在Java当中的体现: 方法就是一种封装 关键字private也是一种封装封装就是将一些细节信息隐藏起来,对于外界不可见。1.1 封装概述概述面向对象编程语言是对客观世界的模拟,客观世界里成员变量都是隐藏在对象... -
java入门(二)_面向对象的三大性
2019-09-08 12:19:17目录 一、封装性 ...封装可以被认为是一个保护屏障,防止该类的代码和数据被外部类定义的代码随机访问。封装的优点:良好的封装能够减少耦合、类内部的结构可以自由修改、可以对成员变量进行更精确的... -
JAVA面向对象三大特征:
2019-03-25 04:08:13封装可以被认为是一个保护屏障,防止该类的代码和数据被外部类定义的代码随机访问。 要访问该类的代码和数据,必须通过严格的接口控制。 封装最主要的功能在于我们能修改自己的实现代码,而不用修改那些调用我们代码... -
Java面向对象三大特性
2021-04-10 16:01:30封装可以被认为是一个保护屏障,防止该类的代码和数据被外部类定义的代码随机访问。 当多个类之间有相同的特征和行为时,可以将相同的内容提取出来组成一个公共类,让对多个类吸收公共类中已有特征和行为而在多个类... -
Java三大特性详解附代码【精】
2020-07-13 20:46:27Java的三大特性 封装 继承 多态 封装 在面向对象程式设计方法中,封装(英语:Encapsulation)是指一种将抽象性函式接口的实现细节部分包装、隐藏起来的方法。 封装可以被认为是一个保护屏障,防止该类的代码和... -
Java初学——面向对象之三大特性
2019-01-27 17:04:01封装可以被认为是一个保护屏障,防止该类的代码和数据被外部类定义的代码随机访问。 要访问该类的代码和数据,必须通过严格的接口控制。 封装最主要的功能在于我们能修改自己的实现代码,而不用修改那些调用我们... -
[Java入门笔记] 面向对象三大特征之:封装
2015-12-21 23:47:00了解封装 什么是封装?...封装可以被认为是一个保护屏障,防止该类的代码和数据被外部类定义的代码随便访问。如果要访问类中的代码和数据,必须要通过严格的控制。 为什么要使用封装? 使用封装... -
面经笔记-1:面向对象编程的三特性:封装、继承、多态
2020-10-28 21:26:52也就是把客观事物封装成抽象的类,并且类可以把自己的数据和方法只让可信的类或者对象操作,对不可信的进行信息隐藏。 Java中用public,protected,,private四种访问权限关键字修饰 意义: 保护或者防止代码(数据... -
天地三才阵——【Java三大特征】
2020-06-19 17:10:55在面向对象程式设计方法中,封装(英语:Encapsulation)是指,一种将抽象性函式接口的实作细节部份包装、隐藏起来的方法,可以被认为是一个保护屏障,防止该类的代码和数据被外部类定义的代码随机访问,要访问该类的... -
Java面向对象
2021-02-19 15:28:29文章目录面向对象接口抽象类java的封装优点Java实现封装的步骤Java的继承继承的类型继承的特性继承的关键字 面向对象 java是一门面向对象的语言,面向对象最重要的三个特性封装,继承和多态。 接口 抽象类 java的... -
Java 语言基础 —— 非常符合中国人习惯的Java基础教程手册
2009-04-28 16:43:18要了解面向对象编程(OOP)的基本概念,需要理解 OOP 的三个主要概念,它们撑起 了整个 OOP 的框架。这三个概念是:封装、继承性和多态性。除此以外,还需了解对象、 类、消息、接口、及抽象等概念。 2.2.1 ... -
Java基础-面向对象-面向对象的特征
2020-12-23 17:41:26Java工程师知识树 / Java基础 ...封装可以被认为是一个保护屏障,防止该类的代码和数据被外部类定义的代码随机访问。 要访问该类的代码和数据,必须通过严格的接口控制。 封装最主要的功能在于可以修改实现代码, -
【Java】15.面向对象之封装(初始化、内部数据、操作方法)
2019-08-13 22:38:56封装可以被认为是一个保护屏障,防止该类的代码和数据被外部类定义的代码随机访问。 要访问该类的代码和数据,必须通过严格的接口控制。 封装最主要的功能在于我们能修改自己的实现代码,而不用修... -
超级有影响力霸气的Java面试题大全文档
2012-07-18 09:47:04声明方法的存在而不去实现它的类被叫做抽象类(abstract class),它用于要创建一个体现某些基本行为的类,并为该类声明方法,但不能在该类中实现该类的情况。不能创建abstract 类的实例。然而可以创建一个变量,... -
java 面向对象 优势_Java面向对象
2021-03-21 11:01:37文章目录面向对象java是一门面向对象的语言,面向对象最重要的三个特性封装,继承和多态。java的封装在面向对象程式设计方法中,封装(英语:Encapsulation)是指一种将抽象性函式接口的实现细节部分包装、隐藏起来的... -
Java面向对象编程(中)
2020-10-11 14:47:56在继承性的特性下,子类拥有父类的属性和方法,而在Java中不同于C++的继承,Java不允许一个类同时继承多个类,但允许一个类同时被多个类继承 继承性的作用: 防止代码的冗余 提供代码的拓展性 注意: 千万不要... -
java面向对象
2020-12-13 21:10:20说道面向对象,大家肯定会想到面向对象的三大基本特征:封装、继承、多态 2.Java 封装 在面向对象设计方法中,封装(英语:Encapsulation)是指一种将抽象性函式接口的实现细节部份包装、隐藏起来的方法。 ① 封装... -
第八周Java作业
2019-10-20 00:42:11本周主题:面向对象程序设计(二) JAVA面向对象三大特性: 一、Java 封装 二、Java 继承 ...封装可以被认为是一个保护屏障,防止该类的代码和数据被外部类定义的代码随机访问。 要访问该类...