第五章 继承
作者:互联网
目录
5.1 类、超类与子类
5.1.1 定义子类
使用关键字 extends 表示继承
在Java中,所有继承都是公共继承,而没有C++中的私有继承和保护继承
关键字 extends 表明正在构造的新类派生于一个已存在的类,这个已存在的类称为超类、基类或父类;新类称为子类、派苏类或孩子类
通过扩展超类定义子类时,只需要指出子类与超类的不同之处
public class Manager extends Employee{
priavte double bonus;
...
public void setBonus(double bonus){
this.bonus = bonus;
}
}
5.1.2 覆盖方法
超类中的有些方法对子类Manager并不一定适用,为此需要一个新的方法来覆盖超类中的这个方法
当我们希望调用超类中的某个方法,而不是子类中的该方法时,可以使用关键字 super 来解决这个问题
super.getSalary();
在子类中可以增加字段、增加方法或覆盖超类的方法,但是继承不会删除任何字段和方法
5.1.3 子类的构造器
public Manager(String name,double salary,int year,int month,int day){
super(name,salary,year,month,day);
bonus = 0;
}
//super关键字在这里表示:“调用超类中带有n、s、year、month、day参数的构造器方法”
//由于Manager不能访问Employee的私有字段,所以必须通过调用一个构造器来初始化参数
使用super调用构造器的语句,必须是子类构造器的第一条语句
如果子类的构造器没有显式地调用超类的构造器,将自动地调用超类的无参数构造器
5.1.4 继承层次
Java不像C++那样支持多重继承,但是它提供了接口实现多重继承的功能
5.1.5 多态
is-a规则:可以用来判断是否应该将数据设计为继承关系
- 子类的每个对象也是超类的对象
- 程序中出现超类的地方都可以用子类对象替换,可以将子类对象赋给超类对象,反之不行
5.1.6 阻止继承:final类和方法
不允许扩展的类被称为final类,如果在定义类的时候使用了final修饰符就表明了这个类是final类
类中的某个特定方法也可以被声明为final。如果这样做,子类就不能覆盖这个方法(final类中的所有方法自动地成为final类)
将方法或类声明为final的主要原因是:确保它们不会在子类中改变语义
5.1.7 强制类型转换
Manager boss = (Manager)e;
进行强制类型转换的唯一原因是:要在暂时忽视对象的实际类型之后使用对象的全部功能
5.1.9 抽象类
使用 abstract 关键字可以声明一个方法,但是不需要实现它
包含一个或多个抽象方法的类本身必须声明为抽象类
抽象方法充当着占位方法的角色,它们在子类中具体实现。
即使不包含抽象方法,也可以将类声明为抽象类
扩展抽象类可以有两种方法:
1、在子类中保留着抽象类中的部分或所有的抽象方法仍未定义,同时将子类标记为抽象类
2、定义全部的方法
抽象类不能实例化
5.1.10 受保护访问
Java中的四个访问修饰符
- private:仅对本类可见
- public:对外部完全可见
- protected:对本包和所有子类可见
- 默认,无修饰符:对本包可见
5.2 Object:所有类的超类
Object类是Java中所有类的始祖,在Java中每个类都扩展了Object,但是并不需要显式的写出来
5.2.1 Object类型的变量
可以使用Object类型的变量引用任何类型的变量
在Java中,只有基本类型不是对象;所有的数组类型,不管是对象数组还是基本类型的数组都扩展了Object类
5.2.2 equals方法
Object类中的 equals 方法用于检测一个对象是否等于另外一个对象。Object类中实现的 equals 方法将确定两个对象引用是否相等
在子类中定义 equals 方法时,首先调用超类的 equals。如果检测失败,对象就不可能相等(超类的方法检测两个对象是否属于同一个类)
5.2.3 相等测试与继承(难)
Java语言规范要求 equals 方法具有下面的特性:
- 自反性:对于任何非空引用x,x.equals(x)返回true
- 对称性:对于任何引用x和y,当且仅当y.equals(x)返回true时,x.equals(y)返回true
- 传递性
- 一致性:如果x和y引用的对象没有发生变化,反复调用x.equals(y)应该返回同样的结果
- 对于任何的非空引用x,x.equals(null)应该返回false
java.util.Arrays;
static boolean equals(xxx[] a,xxx[] b);
//如果两个数组的长度相等,并且对应的位置上的数据元素也相同,则返回true
//数组的元素类型可以是Object,int,long等
java.util.objects
static boolean equals(Object a,Object b);
//如果a和b都是null,返回true;如果只有其中之一为null,则返回false;否则返回a.equals(b)
5.2.4 hashoCde方法
散列码(hash code)是由对象导出的一个整型值。散列码是没有规律的。如果x和y是不同的对象,x.hashCode()与y.hashCode()基本上不会相同
由于hashCode方法定义在Object类中,因此每个对象都有一个默认的散列码,其值由对象的存储地址得出
字符串的散列码由内容导出
数组类型的散列码由数组元素的散列码组成
5.2.5 toString方法
toString方法:返回表示对象值的一个字符串
绝大多数的方法都遵循这样的格式:类的名字,随后是一对方括号括起来的字段值
java.lang.Object;
Class getClass();
//返回包含对象信息的类对象
boolean equals(Object otherObject);
//比较两个对象是否相等,比较内容为对象指向的空间。要在自定义的类中覆盖这个方法
String toString();
//返回表示该对象值的字符串。要在自定义的类中覆盖这个方法
java.lang.Class;
String getName();
//返回这个类的名字
Class getSuperclass();
//以Class对象的形式返回这个类的超类
5.3 泛型数组列表
ArrayList类类似于数组,但在添加或删除元素时,可以自动调整数组容量
5.3.1 声明数组列表
java.util.ArrayList;
ArrayList<E>(); //构造一个空数组列表
ArrayList<E>(int initialCapaity); //用指定容量构造一个空数组列表
boolean add(E obj); //在数组列表的末尾追加一个元素,永远返回true
int size(); //返回当前存储在数组列表中的元素个数
void ensureCapacity(int capacity);
//确保数组列表在不重新分配内部存储数组的情况下,有足够的容量存储给定数量的元素
void trimToSize(); //将数组列表的存储容量削减至当前大小
5.3.2 访问数组列表元素
数组列表自动扩展容器的便利增加了访问元素语法的复杂程度,要使用get和set方法访问或改变数组的元素
java.util.ArrayList; //以类E为例
E set(int index,E obj); //将值obj放置在数组列表的指定索引位置,返回之前的内容
E get(int index); //得到指定索引位置存储的值
void add(int index,E obj); //后移元素,并将obj插入到指定索引位置
E remove(int index); //删除位置的元素,并将后面的元素前移。返回删除的元素
5.3.3 类型化与原始数组列表的兼容性
5.4 对象包装器与自动装箱
所有的基本类型都有一个与之对应的类,Ingeter类对应类型int。这些类称为包装器。
包装器是不可变的,一旦构造了包装器,就不允许更改包装在其中的值。同时,包装器类还是final,因此不能派生它的子类。
var list = new ArrayList<Integer>
//声明Integer的数组列表,但是不能使用 ArrayList<int> 进行声明
自动装箱与自动拆箱
- 包装器类型可以声明为null,所以自动装箱有可能会抛出一个NullPointerException异常
- 如果在一个表达式中混合使用Integer和Double类型,Integer值会拆箱,提升为double,再装箱为Double
- 装箱和拆箱是编译器的工作
java.lang.Integer;
int intValue(); //将这个Integer对象的值作为一个int返回(覆盖了Number类中的intValue类)
static String toString(int i); //返回一个新的String对象,表示指定数值i的十进制表示
static String toString(int i,int radix); //返回数值i基于radix参数指定进制的表示
static int parseInt(String s);
static int parseInt(String s,int radix);
//返回字符串s表示的整数,指定字符串必须表示一个十进制整数,或者radix参数指定进制的表示
static Integer valueOf(String s);
static Integer valueOf(String s,int radix);
//返回一个新的Integer对象,用字符串s表示的整数初始化。指定的字符串必须表示一个十进制整数,或者radix参数指定进制的表示
java.text.NUmberFormat
Number parse(String s); //返回数字值,假设给定的String表示的一个数值
5.5 参数数量可变的方法
//来看看printf方法的定义:
public class PrintStream{
public PrintStream printf(String fmt,Object... args)
{
return format(fmt,args);
}
}
这里的省略号“...”是Java代码的一部分,表明这个方法可以接收任意数量的对象(除fmt参数外)
//一个简单的例代码
public static double max(double... values){
double largest = Double.NEGATIVE_INFINITY;
for(double v : values)if(v>largest) largest = v;
return largest;
}
5.6 枚举类
public enum Size { SMALL,MEDIUM,LARGE,EXTRA_LARGE }
这个声明定义的类型为一个类,它刚好有4个实例,不可能构造新的对象
如果需要的话,可以为枚举类型增加构造器、方法和字段
public enum Size{
SMALL("S"),MEDIUM("M"),LARGE("L"),EXTRA_LARGE("XL");
private String abbreviation;
private Size(String abbreviation) { this.abbreviation = abbreviation; }
public String getAbbreviation() { return abbreviation; }
}
枚举的构造器总是私有的,可以省略private修饰符
所有的枚举类型都是Enum类的子类
java.lang.Enum; //假设存在一个枚举类型E
static Enum valueOf(Class enumClass,String name); //返回给定类中有指定名字的枚举常量
String toString(); //返回枚举常量名
int ordinal(); //返回枚举常量在enum声明中的位置,位置从0开始计数
int compareTo(E other);
//如果枚举常量出现在other之前,返回一个负整数;如果this==other,则返回0;否则返回一个正整数。枚举常量的出现次序在enum声明中给出
5.7 反射
5.7.2 声明异常入门
异常有两种类型:非检查型异常和检查型异常。
对于检查型异常,编译器将会检查你是否知道这个异常并做好准备来处理后果;对于非检查型异常,如越界错误或访问null引用,都属于非检查型异常。
5.8 继承的设计技巧
- 将公共操作和字段放在超类中
- 不要使用受保护的字段
- 使用继承实现“is-a”关系
- 除非所有继承的方法都有意义,否则不要使用继承
- 在覆盖方法时,要保证预期的行为
- 使用多态,不要使用类型信息
- 不要滥用反射
标签:5.1,数组,继承,子类,int,第五章,超类,方法 来源: https://blog.csdn.net/qq_52876054/article/details/122034834