4.1类的继承
类的继承:
- 一种由已有的类创建新类的机制,是面向对象程序设计的基石之一
- 通过继承,可以根据已有类来定义新类,新类拥有已有类的所有功能
- Java只支持单继承,即每个子类只能有一个直接父类
- 父类是所有子类的公共属性及方法的集合,子类是父类的特殊化
- 继承机制可以提高程序的抽象程度,提高代码的可重用性
基类/超类:
被直接或间接继承的类
派生类/子类:
继承其他类而得到的类;继承所有祖先的状态和行为;可以增加变量和方法;可以覆盖(override)继承的方法
派生类对象:
派生类产生的对象;包括与基类相同的接口,可以具有更多的方法和数据成员;包含一个基类类型的子对象。
继承的语法:
class childClass extends parentClass
{
//类体
}
例子4-1
//父类Employee
class Employee
{
int employeeNumber;
String name, address, phoneNumber;
}
//子类Manager
class Manager extends Employee
{
//子类新增加的数据成员
String responsibilities, listOfEmployee;
}
例4-2
package eg4_2;
public class Person{
public String name;
public String getName(){
return name;
}
}
package eg4_2;
public class Employee extends Person{
public int employeeNumber;
public int getEmployeeNumber(){
return employeeNumber;
}
}
package eg4_2;
public class Manager extends Employee{
String responsibilities;
public String getResponsibilities(){
return responsibilities;
}
}
package eg4_2;
public class Tester {
public static void main(String[] args) {
// TODO Auto-generated method stub
Employee li = new Employee();
li.name = "Li Ming";
li.employeeNumber = 123456;
System.out.println(li.getName());
System.out.println(li.getEmployeeNumber());
Manager he = new Manager();
he.name = "He Xia";
he.employeeNumber = 543469;
he.responsibilities ="Internet project";
System.out.println(he.getName());
System.out.println(he.getEmployeeNumber());
System.out.println(he.getResponsibilities());
}
}
例4-2测试结果
Li Ming
123456
He Xia
543469
Internet project
例4-3
(子类不能直接访问从父类中继承的私有属性及方法,但 可以使用公有及保护的方法进行访问)
//A.java
package eg4_3;
public class B {
public int a = 10;
private int b = 20;
protected int c = 30;
public int getB() {
return b;
}
}
//B.java
package eg4_3;
public class A extends B {
public int d;
public void tryVariables() {
System.out.println(a);//允许
System.out.println(b);//不允许
System.out.println(getB());//允许
System.out.println(c);//允许
}
}
隐藏和覆盖:
子类对父类继承来的属性变量及方法可以重新定义
属性的隐藏:
- 子类中声明了与父类中相同的成员变量名,则从父类继承的变量将被隐藏
- 子类拥有了两个相同名字的变量,一个继承自父类,另一个由自己声明
- 当子类执行继承自父类的操作时,处理的是继承自父类的变量,而当子类执行它自己声明的方法时,所操作的就是它自己声明的变量
class Parent{
Number aNumber;
}
class Child extends Parent{
Float aNumber;
}
如何访问被隐藏的父类属性:
调用从父类继承的方法/使用super.属性
例4-4
//A1.java
package eg4_4;
public class A1 {
int x = 2;
public void setx(int i)
{ x = i; }
void printa()
{ System.out.println("A.x="+x); }
}
//B1.java
package eg4_4;
public class B1 extends A1 {
int x = 100;
void printb()
{
super.x = super.x + 10;
System.out.println("super.x="+super.x+"B.x="+x);
}
}
//Tester.java
package eg4_4;
public class Tester {
public static void main(String[] args) {
// TODO Auto-generated method stub
A1 a1 = new A1();
a1.setx(4);
a1.printa();
B1 b1 = new B1();
b1.printb();
b1.printa();
b1.setx(6);
b1.printb();
b1.printa();
a1.printa();
}
}
例4-4测试结果
A.x=4
super.x=12 B.x=100
A.x=12
super.x=16 B.x=100
A.x=16
A.x=4
思路流程:
子类不能继承父类中的静态属性,但是可以对父类中的静态属性进行操作。如:将上例中“int x = 2;”改为“static int x = 2;”得到的结果将是
A.x=4
super.x=14 B.x=100
A.x=14
super.x=16 B.x=100
A.x=16
A.x=16
在上面的结果中,第一行及最后一行都是语句“a1.printa();”输出的结果,显然类B中的printb()方法修改的是类A中的静态属性x
方法覆盖:
- 如果子类不需要使用从父类继承来的方法的功能,则可以声明自己的同名方法,称为方法覆盖
- 覆盖方法的 返回类型、方法名称、参数个数 及 类型 必须和被覆盖的方法一样
- 只需在方法名前面使用不同的类名或不同类的对象名即可区分覆盖方法和被覆盖方法
- 覆盖方法的访问权限可以比被覆盖的宽松,但是不能更为严格
方法覆盖的应用场合:
- 子类中实现与父类相同的功能,但采用不同的算法或公式
- 在名字相同的方法中,要做比父类更多的事情
- 在子类中需要取消从父类继承的方法
方法覆盖的注意事项:
- 必须覆盖的方法:派生类必须覆盖基类中的抽象的方法,否则派生类自身也成为抽象类
- 不能覆盖的方法:基类中声明为final/static的方法
- 如何才能调用被覆盖的方法:super.overriddenMethodName();
有继承时的构造方法 遵循的原则:
- 子类不能从父类继承构造方法
- 好的程序设计方法是在子类的构造方法中调用某一个父类构造方法,调用语句必须出现在子类构造方法的第一行,可使用super关键字
- 如子类构造方法的声明中没有明确调用父类构造方法,则系统在执行子类构造方法时会自动调用父类的默认构造方法(即无参的构造方法)
例4-6
//Person.java
package eg4_6;
public class Person {
protected String name,phoneNumber,address;
public Person() {
this("","","");
}
public Person(String aName,String aPhoneNumber,String anAddress) {
name = aName;
phoneNumber = aPhoneNumber;
address = anAddress;
}
}
//Employee.java
package eg4_6;
public class Employee extends Person {
protected int employeeNumber;
protected String workPhoneNumber;
public Employee() {
//此处隐含调用构造方法Person()
this(0,"");
}
public Employee(int aNumber,String aPhoneNumber) {
//此处隐含调用构造方法Person()
employeeNumber = aNumber;
workPhoneNumber = aPhoneNumber;
}
}
//Professor.java
package eg4_6;
public class Professor extends Employee {
protected String research;
public Professor() {
super();
research = "";
}
public Professor(int aNumber,String aPhoneNumber,String aResearch) {
super(aNumber,aPhoneNumber);
research = aResearch;
}
}
4.2 Object类
object类:
- Java程序中所有类的直接或间接父类,类库中所有类的父类,所有类层次最高点
- 包含了所有Java类的公共属性,构造方法是Object()
Object类包含的主要方法(Object类定义了所有对象必须具有的状态和行为,以下列出较主要的方法):
- public final Class getClass()------获取当前对象所属信息,返回Class对象
- public String toString()------返回当前对象本身的有关信息,按字符串对象返回
- public boolean equals(Object obj)------比较两个对象是否是同一个对象,是则返回true
- protected Object clone()------生成当前对象的一个拷贝,并返回这个复制对象
- public int hashCode()------返回该对象的哈希代码值
- protected void finalize() throws Throwable------定义回收当前对象时对象时所需完成的资源释放工作
不可以覆盖终结方法,即有final修饰的方法
–toString–
public String toString(){
return getClass().getName()+"@"+Integer.toHexString(hashCode());
}//hashCode是一个对象在堆里面对应的一个地址
测试代码:
package Ch4;
public class ObjectToString {
public static void main(String[] args) {
// TODO Auto-generated method stub
ObjectToString ots = new ObjectToString();
System.out.println("ots is "+ots);
System.out.println("ots's toString is "+ots.toString());
}
}
测试结果
ots is Ch4.ObjectToString@27bc2616
ots's toString is Ch4.ObjectToString@27bc2616
有时候要求返回特殊的对象信息,可以重写toString()函数,例如:
//Apple.java
package Ch4;
public class Apple {
private String color;
private boolean ripe;
public Apple(String aColor,boolean isRipe) {
color = aColor;
ripe = isRipe;
}
public String toString() {
if(ripe)
return("a ripe "+color+" apple");
else
return("a not ripe "+color+" apple");
}
}
//AppToString.java
package Ch4;
public class AppToString {
public static void main(String[] args) {
// TODO Auto-generated method stub
Apple a = new Apple("red",true);
Apple b = new Apple("green",false);
System.out.println("a is "+a);
System.out.println("b is "+b);
}
}
测试结果:
a is a ripe red apple
b is a not ripe green apple
-- 相同和同一 –
- 二者相等(equal):两个对象具有相同的类型,及相同的属性值
- 同一(identical):两个引用变量(对象)指向同一个对象
- 关系:两个对象同一,则肯定相等;两个对象相等,不一定同一
- 比较运算符“ == ”判断的是两个对象是否同一
equals方法:
由于Object是类层次结构中的树根节点,因此所有其他类都继承了equals()方法;
Object类中的equals()方法的定义如下,可见,也是用来判断两个对象是否同一
public boolean equals(Object x){
return this==x;
}
equals方法的重写:
判断两个对象各个属性域的值是否相同,不能使用从Object类继承来的equals方法,而需要在类声明中对equals方法进行重写(String类中已经重写了Object类的equals方法,用来判断两个字符是否内容相同)
PS:由于是对Object类中的equals方法进行重写,因此方法定义必须与Object类中的equals方法完全相同
例4-10
//Apple.java
//AppleTest.java
4.7 包的应用
包
为了解决类名冲突
//4.7.1Java基础类库简介
------ 常量 字符串类String
StringBuffer 类的常用方法
数学类(Math)
- 提供一组常量和数学函数,例如:E和PI常数;
- 其中所有的变量和方法都是静态的(static)
- 是终结类,不能派生其他的新类
java中三种计算随机数:
- java.lang.Math.Random();
- java.util.Random类
- 获取系统时间System.currentTimeMillis()
- java.lang.Math.Random();
:调用这个Math.Random()函数能够返回带正号的double值,该值大于等于0.0且小于1.0,即取值范围是[0.0,1.0)的左闭右开区间,返回值是一个伪随机选择的数,在该范围内(近似)均匀分布。 - java.util.Random类
:直接使用Random无法避免生成重复的数字,如果需要生成不重复的随机数序列,需要借助数组和集合类。 - 获取系统时间System.currentTimeMillis()
:java使用 系统时间 获得随机数
// bool[ ]数组默认初始值是false
// 3000ms=3s,因为计算机运行速度特别高,需要延时,否则获得的数相同,导致产生的随机数也会一样
//千年虫?
//时间回归?