java核心技术读书笔记—继承
继承
1 类、超类及子类
1.1 定义子类
在java中,使用关键字extends
进行继承,具体实现方式如下,这里Manager
表示子类,Employee
表示超类,下面所示关系是类Manager
继承于类Employee
。
pubic Manager extends Employee
{}
通过这种继承的方式,子类可以继承很多超类中允许继承的方法和变量,因此子类定义的对象能够直接使用这些方法和变量。
1.2 覆盖方法
当超类中的一些方法不能够满足子类的需求时,可以定义一个一样名字的方法,但是方法中实现内容有所不同,
1.3 子类构造器
同样是一个类,作为子类也是需要一个构造器进行构造对象,不过有一点需要明白的是,每次用子类创建对象的时,均会执行子类构造器之前先执行超类构造器,如此继续往上调用一直到Object
的构造器,等Object
构造完成之后,执行超类构造器,最后执行子类构造器。举个例子,如下
class Animal
{public Animal(){System.out.println("Making an animal");}
}class Dog extends Animal
{public Dog(){System.out.println("Making a Dog");}
}public class Test
{public static void main(String args[]){Dog a=new Dog();}
}
在上述例子中,当创建一个Dog
类的对象时,首先调用Dog
类的构造函数Dog()
,并将其压入栈,接着Dog
会调调用超类的构造函数,将超类的构造函数Animal()
压入栈,最后会调用Object
类的构造函数,并将其压入栈中;接下来就会依次按照先进后出的顺序将这些构造函数出栈,出一次栈就调用相应出栈函数,因此,会先调用超类的构造函数,其次再调用子类的构造函数。
在上面这段中说会调用超类的构造函数,这是怎么回事呢?子类的构造函数在执行的时候,首先均会调用超类的构造函数,具体可以分为两种:
- 第一种,我们可以且必须在子类构造函数中的第一条语句,通过调用
super()
函数的形式调用超类的构造函数(可以是无参构造也可以是有参构造) - 第二种,如果不通过上述方式
显式
调用超类构造函数,系统会自动调用超类的无参构造函数。当然这种情况下一定需要超类有无参构造函数,如果没有无参构造函数系统就会报错
1.4 继承层次
在java中,支持一个超类具有多个子类,但是不支持一个子类继承于多个超类(这一点和C++有所不同)
1.5 多态
在java中,任何对象变量均是多态的,简单来说,就是一个超类的变量既可以引用超类对象
也可以引用子类对象
,相反,一个子类的变量不可以引用超类对象;如下述程序中的超类Animal
与子类Dog
,当超类定义的变量a
引用子类对象时,这时候变量a
是一个超类变量,所以会导致不能调用子类的特有函数bark()
,如果想使用必须将变量a
强制转换为子类;但是呢,变量a
可以调用子类中覆盖超类中的函数,如下面程序中的函数make()
,如果执行a.make()
,则会自动调用子类中的make()
函数,这正是多态神奇的地方!
- 总结以上所说,多态的特点就是超类变量可以引用子类对象,但是在使用超类变量调用方法时,只能调用子类的对超类覆盖的方法,不能调用子类特有的方法
- 如果要想一个超类变量能够使用子类特有的方法,可以将其强制转换为子类类型,如下面程序所示,将
c[0]
由Animal
类型强制转换为Dog
之后(Dog e=(Dog)c[0]
),就可以使用Dog
类中的bark()
方法了
class Animal
{public Animal(){System.out.println("Making an animal");}public void make(){System.out.println("Animal:make()");}public void eat(){System.out.println("Animal:eat()")}}class Dog extends Animal
{public Dog(){System.out.println("Making a Dog");}public void make(){System.out.println("Dog:make()");}public void bark(){System.out.println("Dog:bark()");}public void eat(){System.out.println("Dog:eat()")}
}class Cat extends Animal
{public Cat(){System.out.println("Making a cat");}public void eat(){System.out.println("Cat:eat()");}}public class Test
{public static void main(String args[]){Animal a=new Animal();//超类变量引用超类对象Animal b=new Dog();//超类变量引用子类对象a=b;//超类变量引用子类对象Animal[] c=new Animal[2];c[0]=new Dog();c[1]=new Cat();c[0].eat();//执行Dog类中的eat()函数c[0].bark();//不能执行,因为c[0]还只是一个Animal变量c[1].eat();//执行Cat类中的eat()函数Dog e=(Dog)c[0];e.bark();//将c[0]类型转换为Dog后就可以使用其特有的方法了}
}
1.6 理解方法调用
当如果出现类c
继承于类b
,类b
继承于类a
时,这时候具体的方法调用情况是如何的呢?举例说明。
class Animal
{void makenoise(){System.out.println("Animal:makenoise()");}void eat(){System.out.println("Animal:eat()");}void sleep(){System.out.println("Animal:sleep()");}void roam(){System.out.println("Animal:roam()");}
}class Canine extends Animal
{void roam(){System.out.println("Canine:roam()");}
}class Wolf extends Canine
{void makenoise(){System.out.println("Wolf:makenoise()");}void eat(){System.out.println("Wolf:eat()");}
}public class Test
{public static void main(String args[]){Wolf a=new Wolf();a.makenoise();//调用Wolf类中的makenoise()函数a.roam();//调用Canine类中的roam()函数a.eat();//调用Wolf类中的eat()函数a.sleep();//调用Animal类中的sleep()函数}
}
上述例子表明,当出现多阶继承时,由于子类会继承来自超类的一些方法,所以会从继承级别的最低阶开始往最高阶寻找调用的方法,直到寻找到为止。
1.7 阻止继承
当我们想要使的自己写的类不允许被继承时,可以使用final
对类进行声明,一旦类被声明了final
,就表示该类不允许衍生出任何子类。如下所示。
public final class Excutive extends Manager
{}
//声明final类的方式如上所示
此外,也可以对类中的某个具体方法声明为final
,这样的方法具有什么含义呢?其含义就是,子类中不能覆盖该方法,并且需要说的时final
类中的任何方法均自动的成为final
方法,但是需要注意的是变量不会成为final
。
通过这种方法,可以知道,任何final
类的引用一定是该final
类对象,不可能是其子类对象。如java中的String
类,其也是final
类,因此String
类的引用一定是String
类本身的对象。
1.8 抽象类与方法
- 抽象类是一种
奇怪的类
,为什么这么说呢?因为其不能被初始化,没有这种类的对象可以产生,简单来说,就是不能new
出来。但是,还是可以将这种类作为引用类型,来引用一些子类对象。抽象类的定义如下。
abstract class Canine extends Animal
{}class Dog extends Canine
{}public static void main(String[] args)
{Canine a=new Canine();//编译错误,因为等号右边不能创建抽象类的实例对象Canine b=new Dog();//编译成功,虽然不能创建抽象类的对象,但是可以有抽象类的引用
}
含有大于一个抽象方法的类必须被标记为抽象的,抽象类中可以包含抽象方法和非抽象方法(抽象类中也可以不含有抽象方法);通过上面可以发现,其实抽象类除了继承之外没有其他任何用处。
- 除了抽象类之外,还有抽象方法,抽象方法是没有实体的!如下所示是抽象类的定义方式。另外需要注意的是一旦声明了一个抽象方法,则必须同时将类标记为抽象类(不能在非抽象类中定义抽象方法)
public abstract void eat();
1.9 受保护访问
为了保护变量与方法,最好是将类中的方法或者变量声明为private
,但是这样不利于在继承的时候使得子类利用超类的变量或者方法,所以为了既能使其他类不能使用超类中的一些方法或者变量,且又能使得在子类中能使用一些方法或者变量,可以将这些方法或者变量设置为protected
类型,设置为protected
类型的变量或者方法属于受保护的,其只能在子类中被访问,其他类不能使用。
2 Object:所有类的超类
在java中,Object
类是所有类的超类,也就是说所有的类都是扩展而来的。在我们定义一个类的时候,如果没有没有明确指出其超类,那么这个类的超类默认就是Object
类,但是通常会省略掉。因此可以使用Object
类的变量引用任何类的变量。
public class Cat
{}
//相当于
public class extends Object
{}
其次,在java中只有基本类型
不是对象,如数值、字符以及布尔类型的值这些均不是对象。
2.1 equals方法
在java中,Object
类中提供了比较两个对象是否相等的方法,即equals()
,该方法在检测时,如果两个对象具有相同的引用,则认为是相等的。
2.2 hashCode方法
hashCode
称为散列码,其是由一个对象导出的整型值,并且这个值是对象的存储地址。
2.3 toString方法
在Object
类中,toString()
可以有效返回对象值的字符串。
3 泛型数组列表
为了能够动态更改数组大小的问题,在java中定义了一个称为ArrayList
的类,这种类能够实现动态的添加于删除数组中的元素。ArrayList
类是一个采用类型参数的泛型类,使用方式如下。
ArrayList<Employee> staff=new ArrayList<>();
这种泛型类中具有很多操作方法,用于添加元素,删除元素等等。
add(int index,E obj)
,在指定位置添加元素size()
,返回数组中的元素个数ensureCapacity()
,用于确定数组的大小- 还可以和定义一般数组一样,定义泛型数组,如
ArrayList<Employee> staff=new ArrayList<>(50)
,但是这里和一般的定义数组不同,这里定义的大小表明其具有存储50个数据的能力,在这些空间使用完后,还会继续分配空间使用;相反,一般的定义数组不同,定义多大的空间,只能使用这么大的空间,一旦超过了就不行 set(int index,E obj)
,用于设置指定位置的元素值,将覆盖原来的元素E get(int index)
,将返回指定位置的元素值E remove(int index)
,删除指定位置上的元素,后面的元素会向前移动一个位置
4 对象包装器与自动装箱
有时候我们想要将基本数据类型当做对象进行处理,因此为了实现这种转换。在java中,所有的基本数据类型均有个与之相对应的包装类
,这些类也称为包装器
。如下所示是基本数据类型的包装器
Boolean
Character
Byte
Short
Integer
Long
Float
Double
如下述所示,包装与解开包装
Integer data=new Integer(99);//将改值99进行包装
int d=data.intValue();//解开包装,获得d等于99
- 在自动包装出现之前,基本数据类型与包装器是是严格区分开的,如下面所示
ArrayList array=new ArrayList();
array.add(new Integer(999));//必须将999转换为Object类型
Integer one=(Integer)array.get(0);//取出的时候必须将其转换为Integer
int oneint=one.intValue();//将Integer转换为int
有了自动包装之后,就没有必要按照上面严格讲数据与类型区分开,如下所示
ArrayList<Integer> listnum=new ArrayList<Integer>();
listnum.add(1999);//int数据自动转换为Integer
int listNumber=listnum.get(0);//Integer自动转换为int
- 在上面程序中,
listnum.add(1999)
这条语句将自动转换为listnum.add(Integer.valueOf(1999))
,这就叫做自动装箱
- 在上面程序中,
listnum.get(0)
这条语句将自动转换为listnum.get(0).intValue()
,这就叫做自动拆箱
此外还有一些包装类中还有一些静态方法,如parseInt()
、parseDouble()
等等,这些方法可以将字符串转换为int
或者double
类型,如下面所示
String str="9";
int strNum=Integer.parseInt(str);
String str1="123.45";
double strNum1=Double.parseDouble(str1);
反过来,我们也可以将int
或者double
转换为字符串类型,如下面所示
double dou0=123.45;
String str0=""+dou0;//第一种
String str1=Double.toString(dou0);//第二种使用Double类中的静态成员方法
java核心技术读书笔记—继承相关推荐
- java核心技术读书笔记1
数据类型 整型 int 存储要求:4byte 取值范围:-2147483648 -- 2147483647(超过20亿) short 存储要求:2byte 取值范围:-32768 -- 32767 l ...
- Java核心技术读书笔记01
Volume I Chapter 1 An Introduction to Java • 1.1 Java as a Programming Platform • 1.2 The Java 'Wh ...
- java核心技术读书笔记(第二天:基本程序设计结构)
java基本程序设计结构
- java虚拟机读书笔记 第三章 垃圾收集器和内存分配策略
java虚拟机读书笔记 第三章 垃圾收集器和内存分配策略 GC需要完成的三件事情:哪些内存需要回收.什么时候回收.如何回收 垃圾回收器在对堆进行回收前,首先要确定那些对象存活,哪些对象已经死去,判断的 ...
- Core Java 8 读书笔记-Networking编程
Core Java 8 读书笔记-Networking编程 作者:老九-技术大黍 原文:Core Java 8th Edition 社交:知乎 公众号:老九学堂(新人有惊喜) 特别声明:原创不易,未经 ...
- Java 内存分配——Thinking in Java 4th 读书笔记
做开发多年,一直忙于项目,从没好好的整理知识,从现在开始,尽量每周多抽时间整理知识,分享在博客,在接下来的博客中,我将为大家分享我读<Java编程思想4th>英文版读书笔记,一来便于知识的 ...
- Java核心技术卷一笔记
Java核心技术-卷一学习笔记 文章目录 Java核心技术---卷一学习笔记 前言 一.第一章Java程序设计 标题Java具有的特性: 二.第二章Java程序设计环境 JDK和Jre的区别 第三章J ...
- Java基础读书笔记
Java核心技术卷I 一.Java基础 二.java深入 三.图形程序设计Swing 一.Java基础 1,命名规范:类名首字母大写,若多个单词组成,每个单词首字母大写: 2,注释三方法:句:// 段 ...
- 【学习笔记】java核心技术学习笔记整理
<java核心技术> 花了半天到一天又认真读了一下java核心技术中的类部分,感觉最近编程时候好多迷迷糊糊,"这样对不对呢,试一试.怎么不对呢"这类的迷糊问题原来都早 ...
最新文章
- PHP开发者应了解的24个库
- 说说数据库连接池工作原理和实现方案?
- 【行业报告】基于社交图谱关系的反欺诈产品应用——青云
- JavaFX图表(六)之条形图
- Python系列文章
- 【BZOJ3050】Seating,线段树
- mysql主主复制半同步_mysql主从复制中的半同步复制
- 累加List对象中的某一个值
- Forrester报告:人工智能将取代6%的工作岗位
- 解决安卓全屏问题:关键在于如何隐藏状态栏
- [题解]第十一届北航程序设计竞赛预赛——I.神奇宝贝大师
- <Python启发式自动化>之钉钉推送
- [年终总结]这就是2016的我
- 微积分 —— 曲率与曲率半径
- ICCV 2021 |首届 SoMoF 人体序列预测比赛冠军方案分享
- 使用navicat导入SQL语句的教程
- 职场智慧:君子应处木雁之间,当有龙蛇之变
- Nginx+Tomcat负载均衡、动静分离
- 机器学习理论基础学习10--- 高斯混合模型GMM
- 如何快速查询全部快递单号物流信息