Java核心技术-继承

1、 定义子类:public class Manager extends Employee{ 方法 域 }
Java中的继承都是公有继承
已存在的类:超类 ( superclass)、 基类(base class) 或父类(parent class)
新的类:子类(subclass)、 派生类 (derivedclass) 或孩子类(child class)
子类比超类拥有的功能更加丰富。
超类的对象不能使用派生类的方法,因为不是再超类里面定义的。派生类可以使用超类的方法,继承过来了
2、 覆盖方法:
派生类的方法不能直接方法访问超类的私有域,要通过公共接口,
public double getSalaryO {
double baseSalary = super.getSalaryO;// 通过super和接口,获取到超类中的salary
baseSalary + bonus;
}
3、 子类构造器
public Manager(String name, double salary, int year, int month, int day) {
super(name, salary, year, month, day);
bonus = 0;
}
这里的super是“ 调用超类 Employee 中含有 n、s、year month 和 day 参数的构造器” 的简写形式。
使用 super 调用构造器的语句必须是子类构造器的第一条语句。
如果子类的构造器没有显式地调用超类的构造器, 则将自动地调用超类默认(没有参数) 的构造器。 如果超类没有不带参数的构造器, 并且在子类的构造器中又没有显式地调用超类的其他构造器,则编译错误。
4、多态
一个对象变量(例如, 变量 e) 可以指示多种实际类型的现象被称为多态(polymorphism)。 在运行时能够自动地选择调用哪个方法的现象称为动态绑定(dynamic binding)。
变量 stafflO] 与 boss 引用同一个对象。但编译器将 staff[0]看成 Employee对象
boss.setBonus(5000); // OK
staff[0].setBonus(5000); // Error
不能将一个超类的引用赋给子类变量。例如,下面的赋值是非法的 Manager m = staff[i]; // Error 原因很清楚:不是所有的雇员都是经理。 如果赋值成功,m 有可能引用了一个不是经理的 Employee 对象, 当在后面调用 m.setBonus(…) 时就有可能发生运行时错误。
子类数组的引用可以转换成超类数组的引用, 而不需要采用强制类型转换。 但是实际含义可能有一些问题,两个数组引用同一个对象,赋值了超类,但引用派生类方法就不对了。
5、方法调用
1)查找所有该方法名的方法,包括该类和其超类,然后匹配参数,选择匹配的参数类型,调用该方法。
如果编译器没有找到与参数类型匹配的方法, 或者发现经过类型转换后 有多个方法与之匹配, 就会报告一个错误。
2)静态绑定: 是 private 方法、 static 方法、final 方法或者构造器, 那么编译器将可以准确地知道应该调用哪个方法。
3)超类与派生类定义了相同参数类型的相同方法,派生类对象调用该方法时,执行派生类的方法。
4)虚拟机预先为每个类创建了一个 方法表(method table), 其中列出了所有方法的签名和实际调用的方法。时间开销小。
5)在覆盖一个方法的时候,子类方法不能低于超类方法的可见性。特别是, 如果超类 方法是 public, 子类方法一定要声明为 public。
经常会发生这类错误:在声明子类方法的时 候, 遗漏了 public 修饰符。此时,编译器将会把它解释为试图提供更严格的访问权限。
6、阻止继承:final
不允许扩展的类被称为 final 类。public final class Executive extends Manager{ },不会被继承。
类中的特定方法也可以被声明为 final。如果这样做,子类就不能覆盖这个方法。
将方法或类声明为final 主要目的是: 确保它们不会在子类中改变语义。
7、类型转换
Manager boss = (Manager) staff[0]:
将一个了 -类的引用赋给一个超类 变量, 编译器是允许的。但将一个超类的引用赋给一个子类变量, 必须进行类型转换, 这样 才能够通过运行时的检査。
1)只能在继承层次内进行类型转换。
2)在将超类转换成子类之前,应该使用 instanceof进行检查。
if (staff[1 ] instanceof Manager) {
boss = (Manager) staff[1 ]:

}
8、抽象类abstract
除了抽象方法之外,抽象类还可以包含具体数据和具体方法。
person与子类继承图
抽象类例子代码
9、子类可以直接访问声明为protected的域,不能访问其他域。
下面归纳一下 Java 用于控制可见性的 4 个访问修饰符:
1 ) 仅对本类可见 private。
2 ) 对所有类可见 public:
3 ) 对本包和所有子类可见 protected。
4 ) 对本包可见— —默认(很遗憾), 不需要修饰符。
10、Object超类
Object 类是 Java 中所有类的始祖, 在 Java 中每个类都是由它扩展而来的。但不用写extends。如果没有明确地指出超类,Object 就被认为是这个类的超类。
只有基本类型(primitive types) 不是对象, 例如,数值、 字符和布尔类型的值都不是对象。 所有的数组类塱,不管是对象数组还是基本类型的数组都扩展了 Object 类。
11、equals
Object 类中的 equals方法用于检测一个对象是否等于另外一个对象。在 Object 类中,这 个方法将判断两个对象是否具有相同的引用。如果两个对象具有相同的引用, 它们一定是相等的。
为了防备值可能为 null 的情况,Objects.equals(a,b) 。如果两个参数都不为 null, 则调用 a.equals(b)。
12、 hashCode 方法
如果 x 和 y 是 两个不同的对象, x.hashCode( ) 与 y.hashCode( ) 基本上不会相同。
13、 toString 方法
它用于返回表示对象值的字符串。
绝大多数(但不是全部)的 toString方法都遵循这样的格式:类的名字,随后是一对方括号括起来的域值。
public String toStringO {
return getClassO.getNameO + “[name=” + name +'salary: " + salary + “,hireDay=” + hireDay + T;
}
toString方法也可以供子类调用。 超类使用了 getClass( ).getName( ), 那么子类只要调用 super.toString( )就可以了。
public class Manager extends Employee{
public String toStringO {
return super.toStringO + M[bonus=" + bonus + T;
}
}
Manager 对象将打印输出如下所示的内容: Manager[name=…,salary=…,hireDay=…][bonus=…]
数组:是调用静态方法 Arrays.toString 例:String s = Arrays.toString(luckyNumbers);
多维数组:要调用 Arrays.deepToString 方法
在这里插入图片描述
14、 泛型数组列表ArrayList
它使用起来有点像数组,但在添加或删除元素时, 具有自动调节数组容量的 功能,而不需要为此编写任何代码。
ArrayList 是一个采用类型参数(type parameter) 的泛型类(generic class)。为了指定数 组列表保存的元素对象类型,需要用一对尖括号将类名括起来加在后面。例:ArrayList staff = new ArrayList0;
add添加元素:staff.add(new Employee(“Harry Hacker”, •••)); 如果数组满了,就新建一个更大的数组,把小的拷贝进去。
ensureCapacity:staff.ensureCapacity(100);
这个方法调用将分配一个包含 100 个对象的内部数组。然后调用 100 次 add, 而不用重新分 配空间。
还可以把初始容量传递给 ArrayList 构造器: ArrayList staff = new ArrayListo(lOO);
size方法将返回数组列表中包含的实际元素数目。例如, staff,sizeO 将返回 staff 数组列表的当前元素数量,它等价于数组 a 的 a.length。
一旦能够确认数组列表的大小不再发生变化,就可以调用 trimToSize方法。这个方法将 存储区域的大小调整为当前元素数量所需要的存储空间数目。
在这里插入图片描述
15、 staff.set(i, harry): set改变i位置的值,添加只能是add,get获取
在这里插入图片描述
16、对象包装器与自动装箱
有时, 需要将 int 这样的基本类型转换为对象。所有的基本类型都冇一个与之对应的类。 例如,丨nteger 类对应基本类型 int。通常, 这些类称为包装器 ( wrapper) 这些对象包装器类 拥有很明显的名字:Integer、Long、Float、Double、Short、Byte、Character、Void 和 Boolean (前 6 个类派生于公共的超类 Number)。对象包装器类是不可变的,即一旦构造了包装器,就不 允许更改包装在其中的值。同时, 对象包装器类还是 final, 因此不能定义它们的子类。
设想定义一个整型数组列表。而尖括号中的类型参数不允许是基本类型。
不允许写成 ArrayList。答案:ArrayList list = new ArrayList<>();
自动装箱:调用 list.add(3);将自动地变换成 list.add(Integer.value0f(3));
自动拆箱: 当将一个 Integer 对象赋给一个 int 值时,int n = list.get(i); 翻译成 int n = list.get(i).intValue();
如果在一个条件表达式中混合使用 Integer 和 Double 类型, Integer 值就会拆箱, 提升为 double, 再装箱为 Double。
将字符串转换成整型:int x = Integer.parselnt(s);
有些人认为包装器类可以用来实现修改数值参数的方法, 然而这是错误的。
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
17、枚举类
两个枚举类型的值时, 永远不需要调用 equals, 而是直接使用“ = =” 。
每个枚举类型都有一个静态的 values方法, 它将返回一个包含全部枚举值的数组。 例 Size[] values = Size.valuesO;
ordinal 方法返冋 enum 声明中枚举常量的位置, 位置从 0 开始计数。 例如: Size. MEDIUM. ordinal() 返回 1。
在这里插入图片描述
18、反射:能够分析类能力的程序称为反射。
反射机制可以用来:
•在运行时分析类的能力。
•在运行时查看对象, 例如, 编写一个 toString方法供所有类使用。
•实现通用的数组操作代码。
•利用 Method 对象, 这个对象很像中的函数指针。
19、class类
在程序运行期间,Java运行时系统始终为所有的对象维护一个被称为运行时的类型标识。 这个信息跟踪着每个对象所属的类。保存这些信息的类被称为 Class。
20、捕获异常
异常有两种类型: 未检查异常和已检查异常。
将可能抛出已检査异常的一个或多个方法调用代码放在 try块中,然后在 catch 子句中提 供处理器代码。
在这里插入图片描述
21、检查类的结构
在java.lang.reflect 包中有三个类 Field、Method 和 Constructor 分别用于描述类的域、 方 法和构造器。 这三个类都有一个叫做 getName 的方法, 用来返回项目的名称。Held 类有一 个 getType 方法, 用来返回描述域所属类型的 Class 对象。Method 和 Constructor 类有能够 报告参数类型的方法,Method 类还有一个可以报告返回类型的方法。这 <个类还有一个叫 做 getModifiers 的方法, 它将返回一个整型数值,用不同的位开关描述 public 和 static 这样 的修饰符使用状况。另外, 还可以利用java.lang.refleCt 包中的 Modifiei•类的静态方法分析 getModifiers返回的整型数值。
Class类中的 getFields、 getMethods 和 getConstructors方 法 将 分 别 返 回 类 提 供 的 public 域、 方法和构造器数组, 其中包括超类的公有成员。Class 类的 getDeclareFields、 getDeclareMethods 和 getDeclaredConstructors方法将分别返回类中声明的全部域、 方法和构 造器, 其中包括私有和受保护成员,但不包括超类的成员。
在这里插入图片描述
在这里插入图片描述
22、查看对象域的关键方法是 Field类中的 get 方法。
get方法还有一个需要解决的问题。name 域是一个 String, 因此把它作为 Object 返回 没有什么问题。但是, 假定我们想要查看 salary 域。它属于 double 类型,而 Java中数值类 型不是对象。要想解决这个问题, 可以使用 Field 类中的 getDouble方法,也可以调用 get 方法,此时, 反射机制将会自动地将这个域值打包到相应的对象包装器中,这里将打包成 Doubleo。
在这里插入图片描述
23、Array类中的静态方法 newlnstance, 它能够构造新数组。在调用它时必须提供两个参数,一个是数组的元素类型,一个是数组的 长度。 例:Object newArray = Array.newlnstance(componentType, newLength);
获取长度类型:可以通过调用 Array.getLength(a) 获得数组的长度, 也可以通过 Array类的静态 getLength 方法的返回值得到任意数组的长。
获取参数类型:1 ) 首先获得 a 数组的类对象。 2 ) 确认它是一个数组。 3 ) 使用 Class 类(只能定义表示数组的类对象)的 getComponentType方法确定数组对应 的类型。
在这里插入图片描述
24、继承的设计技巧
1.将公共操作和域放在超类
2. 不要使用受保护的域
3. 使用继承实现“ is-a” 关系
4. 除非所有继承的方法都有意义, 否则不要使用继承
5. 在覆盖方法时, 不要改变预期的行为
6. 使用多态, 而非类型信息
7. 不要过多地使用反射

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值