Java探索之旅(8)——继承与多态
1父类和子类:
❶父类又称基类和超类(super class)子类又称次类和扩展类。同一个package的子类可以直接(不通过对象)访问父类中的(public,缺省,protected)数据和方法。
❷扩展关键字:extends。倘若子类Circles,父类GeometricObject。定义:
public class Circles extends GeometricObject
❸Java只容许单一继承,即一个类只能继承自1个父类。多重继承使用接口实现。
2.子类使用父类的构造函数
❶super关键字:调用父类的构造方法----super()和super(parameters)分别可在子类构造函数中显式地调用父类的构造方法。注意必须出现在子类构造方法的第1行。
❷构造方法链:构造一个类,会继承链中各层次基类的所有构造方法。构造子类对象时,系统会首先调用父类的构造方法,以此嵌套调用至最前一层父类。这里的构造方法隐式为无参构造方法。
❸应该为各类提供无参数构造方法。倘若某个仅有带参构造法的派生类作为基类派生,由于系统不再默认提供无参构造法,故构造方法链在此会出现编译错误。
3.覆盖与重载
❶方法覆盖:即子类修改父类的实例方法。可覆盖的方法要求是可访问的,且子类的覆盖不能削弱父类方法的访问特性(即父类的protected方法,子类覆盖可以public和protected;父类的public方法,子类只能是public)。
为了覆盖父类方法,必须具有相同的签名,方法名,返回类型。倘若签名不同,则变为重载。
❷静态方法不能被覆盖。如果父类的静态方法在子类中重定义(仍旧要求同名同签名同返回类型),则父类的静态方法将会被隐藏,但是可以使用【父类名+'.'+静态方法名】显式调用。
父类和子类同名的静态方法,若返回类型相异,直接导致出错,若不同的签名则是重载而非覆盖。
public class StudyInheritance{
public static void main(String[] args)
{A I=new A();//先调用C的无参构造函数
A.p();//调用的为A的静态方法,基类C的被隐藏
C.p();//使用类名调用C的静态方法}} class C
{protected int data;
C(){System.out.println("Call C Constructor1!");}
C(int d){data=d;System.out.println("Call C Constructor!2");}
protected static void p(){System.out.println("static C method p");}} class A extends C
{A(){System.out.println("Call A Constructor!");}
public static void p(){
System.out.println("static A method p");}}
输出:
Call C Constructor1!
Call A Constructor!
static A method p
static C method p
4.多态与动态绑定
❶面向对象的3个特点:封装、继承和多态。
❷多态性:使用父类型的地方(比如父类为函数参数)都可以使用子类型,即父类型的变量可以引用子类的变量。
❸动态绑定:如前描叙,一个方法可以在父类定义但是在子类覆盖。但是子类对象优先使用子类的(覆盖父类的)方法,类似C++的虚函数。
❹Java中未指定继承性的类,默认其父类是java.lang.Object。即所有的类均是Object类的子类,即他们都继承了Object类的toString()函数,该方法返回“对象所属派生类+@+16进制地址”。
例如:对于Object中方法toString()。倘若有一个类A派生自Object,中间有若干层派生,则基类Object中的public函数toString()被A的toString()覆盖。那么究竟使用基类还是派生类的toString呢?
String str=O.toString();
Object Obj=new A();
注意到对象Obj的声明类型为Object,实际类型是A。实际上Obj使用的toString(),由实际使用类型(即 A)决定的,即动态绑定。Java虚拟机将会从类A开始,依次向每一层基类回溯,找到第一个toString()执行。
5.对象转换和instanceof运算符
❶一般而言。将变量定义为父类型引用,这就可以指向任意子类型的对象。若要使用派生类的函数,必须显式将【声明为基类引用变量,但是实际指向派生类】的引用,即显式转换。如下:
class A extends Obeject
{int data;
function(){.........}; }
Obeject myObject= new A();//隐式转换,基类引用变量指向派生类对象
if(myObject instanceof A)
((A)myObject).function();//为了使用派生类的函数,必须显式说明
❷是声明类型决定在编译时候匹配哪个方法,因此必须显式地告诉编译器,基类型引用变量myObeject具体指向哪一类型的对象,然后才能调用A区别于基类Obeject的成员函数(即不是覆盖函数,而是基类没有的数据和方法,即所谓子类的特性)。
关键字 instanceof 判断声明的基类类型引用变量,是否实际指向某个派生类的对象。
❸动态绑定决定调用最靠近子类对象的覆盖函数。对象转换则用来调用子类中的特性数据域和方法域
6.Object中的equals方法
❶作用:判断两个引用变量是否指向同一个对象(等同“==”)。返回true,否则返回false。并没有实际检查是否内容相同。默认实现为:
public boolean equals(Object obj)
{return (this==obj);}
public class Animal{........}
Animal animal1=new Dog();
Animal animal2=new Cat();
Animal animal3=animal1; animal1==animal2 (False)
animal1.equals(animal2) (False) animal1==animal3 (True)
animal1.equals(animal3) (True)
❷JDK类中有一些类覆盖了Object类的equals()方法。比较规则为:如果两个对象的类型一致且内容一致,则返回true。这些类有:java.io.file,java.util.Date,java.lang.string,包装类(Integer,Double)。
相反,“==”此时不具备内容比较功能。
Integer int1=new Integer(1);
Integer int2=new Integer(1); String str1=new String("hello");
String str2=new String("hello"); int1==int2;//false,不同引用对象
int1.equals(int2);//TRUE,相同内容 str1==str2;//False,不同引用对象
str1.equals(str2);//True,相同内容
❸可自定义覆盖object类的equals()方法,重新定义比较规则。
下面Person类的equals()比较规则为:只要两个对象都是Person类,并且他们的属性name都相同,则比较结果为true,否则返回false
public class Person{
private String name;
Person(String name)
{this.name=name;}
public boolean equals(Object o){
if (this==null) return true;
else if (!o instanceof Person) return false;
final Person other=(Person)o;
if (this.name().equals(other.name()))
return true;
else
return false;
}
}
注意:在重写equals方法时,要注意满足离散数学上的特性
①自反性:对任意引用值X,x.equals(x)的返回值一定为true.
②对称性:当且仅当y.equals(x)返回值为true时,x.equals(y)的返回值一定为true;
③传递性:如果x.equals(y)=true, y.equals(z)=true,则x.equals(z)=true
④一致性:如果参与比较的对象没任何改变,则对象比较的结果也不应该有任何改变
⑤非空性:任何非空的引用值X,x.equals(null)的返回值一定为false
7.防止扩展和覆盖
❶为了防止类的扩散,使用final修饰符表明一个类是终极类。如Math类就是终极类。
final public class{........};
❷final关键字也可以用来定义终极方法,其不能被子类方法覆盖
public final void function{......}
❸所有的修饰符中,只有final还可以修饰方法的局部变量,所谓的终极局部变量即常量。
8.实例
❶定义Person类。数据域为姓名、地址、电话、邮箱
❷扩展Student。数据域还包括班级
❸扩展Employ。数据域还包括办公室、工资、受聘日期。
❹使用super关键字调用父类构造函数和父类被覆盖的方法toString()。
❺使用instanceof关键字判断基类引用变量的具体指向
package test11_2;
public class Person {
protected String name;
protected String address;
protected String phone;
protected String email; Person(){this(null,null,null,null);}//无参调用有参
Person(String a,String b,String c,String d)
{name=a;address=b;phone=c;email=d;} public String getName(){return this.name;}
public String getAddress(){return this.address;}
public String getPhone(){return this.phone;}
public String getEmail(){return this.email;} public String toString()
{
return name+"\nAddress :"+address+"\nPhone:"+phone+"\nEmail :"+email;
}
} class Student extends Person
{
protected static int classState;
Student(){classState=1;}
Student(String a,String b,String c,String d,final int e)
{super(a,b,c,d);//super调用父类构造函数
classState=e;} public int getClassState(){return Student.classState;} public String toString()
{return "Student---"+super.toString()+"\nClass :"+classState;}//函数覆盖
} class Employ extends Person
{
protected String office;
protected int salary;
MyData data;
Employ(){this(null,null,null,null,null,0,null);}//无参调用有参
Employ(String a,String b,String c,String d,String e,int f,MyData g)
{super(a,b,c,d);//super调用父类构造函数
this.office=e;
this.salary=f;
this.data=g;}
public String toString()
{return "Employ---"+super.toString()+"\nOffice :"+office+"\nSalary :"+salary+"\n"+data.toString();}
} class MyData
{
protected int year,month,day;
MyData(){this(0,0,0);}
MyData(int a,int b,int c){year=a;month=b;day=0;}
public String toString()
{return "The Hired data is :"+year+"-"+month+"-"+day;}
}
测试类
package test11_2;
public class TestPerson {
public static void main(String[] args)
{
//声明为基类引用,指向子类对象
Person obj1=new Student("李四","湖北荆门","182155107","abcde@163.com",3);
Person obj2=new Employ("王五","湖北孝感","155456782","CHpdn@live.com","KB545",12000,new MyData(2011,2,3)); print(obj1);
print(obj2);
} // instanceof 判断具体实例对象
static void print(Person obj)
{
if(obj instanceof Student)
System.out.println(((Student)obj).toString());//(Student)类型显式转换
else if(obj instanceof Employ)
System.out.println(((Employ)obj).toString());//(Employ)类型显式转换
else if(obj instanceof Person)
System.out.println(obj.toString());
else
System.out.println("Wrong input!");
}
}
Java探索之旅(8)——继承与多态的更多相关文章
- Java—类的封装、继承与多态
一.类和对象 1.类 类是数据以及对数据的一组操作的封装体. 类声明的格式: 类声明 { 成员变量的声明: 成员方法的声明及实现: } 1.1 声明类 [修饰符] class 类<泛型> ...
- java复习(5)---接口、继承、多态
Java作为完全面向对象语言,接口.继承和多态是三个非常重要的概念. 1.继承. (1)关键字: extends (2)子类用super()调用父类构造函数,用super().方法 调用父类的成员方法 ...
- 浅析Java三大特性封装、继承、多态,及作业分析
前言 本次博客衔接上次博客,作为这一阶段Java学习的分析.上一篇博客着重介绍了Java的OO编程思维,面向对象与面向过程的区别.本篇博客重心在Java的三大技术特性,附带作业分析. Java三大特性 ...
- java面向对象(封装,继承,多态,抽象,接口的定义和实现)
1.封装 在面向对象程式设计方法中,封装(英语:Encapsulation)是指,一种将抽象性函式接口的实作细节部份包装.隐藏起来的方法. 封装可以被认为是一个保护屏障,防止该类的代码和数据被外部类定 ...
- Java基础之浅谈继承、多态
一.继承的理解 继承:简单通俗的来讲,继承就是一个类继承另一个类,通常用extends表示继承. 继承的类叫子类,被继承的类叫父类. 子类可以使用父类的变量和方法,同时也可以重写父类的方法. 在Jav ...
- Java 三大特性——封装、继承、多态
一.封装 封装,实际就是把属于同一类事物的共性(包括属性与方法)归到一个类中,以方便使用. 概念:在面向对象程式设计方法中,封装(英语:Encapsulation)是指,一种将抽象性函式接口的实作细节 ...
- 九、Java基础---------面向对象封装、继承、多态
封装 1.1 基本概念 封装(encapsulation)是面向对象三大特征之一,它是指将对象的状态信心隐藏在对象的内部,不允许外部直接进行访问,而是通过该类提供的方法来实现对内部信息的操作和访问. ...
- java 面对对象(抽象 继承 接口 多态)
什么是继承? 多个类中存在相同属性和行为时,将这些内容抽取到单独一个类中,那么多个类无需再定义这些属性和行为,只要继承那个类即可. 多个类可以称为子类,单独这个类称为父类.超类或者基类. 子类可以直接 ...
- java类的封装、继承、多态
一.封装(encapsulation) 封装性就是把类(对象)的属性和行为结合成一个独立的相同单位,并尽可能隐蔽类(对象)的内部细节,对外形成一个边界,只保留有限的对外接口使之与外部发生联系.封装的特 ...
随机推荐
- 《UNIX网络编程》daytimetcpcli测试
对于刚刚接触网络的人来说,<UNIX网络编程>中第一个例子(daytimetcpcli)可能就测试不通过.也许你试着继续向后读来,自己写一个服务程序来解决这个问题,但是daytime服务也 ...
- BestCoder 1st Anniversary 1004 Bipartite Graph 【二分图 + bfs + 良好的逻辑思维 】
题目地址:http://bestcoder.hdu.edu.cn/contests/contest_showproblem.php?cid=610&pid=1004 问题描述 Soda有一个$ ...
- Nginx Rewrite语法详解
重写中用到的指令 if (条件) {} 设定条件,再进行重写 set #设置变量 return #返回状态码 return 403; break #跳出rewrite rewrite #重写 I ...
- Storm- 使用Storm实现词频汇总
需求:读取指定目录的数据,并实现单词计数的功能 实现方案: Spout来读取指定目录的数据,作为后续Bolt处理的input 使用一个Bolt把input 的数据,切割分开,我们按照逗号进分割 使用一 ...
- JQUERY获取html标签自定义属性值或data值
//获取属性值 1 <div id="text" value="黑哒哒的盟友"><div> jQuery取值: $("#tex ...
- java:Map借口及其子类HashMap四
java:Map借口及其子类HashMap四 使用非系统对象作为key,使用匿名对象获取数据 在Map中可以使用匿名对象找到一个key对应的value. person: public class Ha ...
- HTML5中Modernizr类库的作用和使用
Modernizr 是一个用来检测浏览器功能支持情况的JavaScript 库.通过这个库我们可以检测不同的浏览器对于HTML5特性的支持情况. 使用Modernizr类库和使用其他第三方类库的方法是 ...
- 用cookie登录慕课网络教学中心刷评论
声明:本文仅供学习参考 我们学校和的网络教学平台是在慕课网上的,需要登录到慕课网的教学平台以后,拿到cookie 注意:没次提交后需要休眠,否则刷评论过快会被系统发现 如果请求太快,很容易被系统发现( ...
- python中的yield关键字
yield关键字一直困扰了我很久,一直也没有弄明白,现在将暂时理解的yield记录如下,供参考: 关键词:可迭代对象,生成器,迭代器 一.可迭代对象: 可迭代对象:可迭代对象是一个泛称,只要可以用fo ...
- 05 - Django应用第二步
知识点 1) 数据库的配置 涉及到INSTALL_APPS的配置等 初次创建数据的命令 2) 模型的编写 模型的创建方式, 写一个类继承自models.Model 模型的数据类型 外键 自动创建ID列 ...