继承与多态
文章目录
1.1继承
Java中不支持多继承,子类只能有一个父类或者没有父类。
1.1.1Java继承的实现
定义类时通过extends关键字指明其要继承的父类。
子类可以访问:
- 子类中直接定义的成员
- 父类中的非私有成员(除构造方法)
【注意】 子类无法继承父类的私有属性,也无法直接访问父类的私有属性,但如果父类中有public修饰的对私有属性的get和set的方法,子类便可以通过该方法间接访问父类的私有属性。
【例如】
class Person {
private String name;
private int age;
public String getName() {
return name;
}
public int getAge() {
return age;
}
public void setName(String name) {
this.name = name;
}
public void setAge(int age) {
this.age = age;
}
}
class Student extends Person{
}
public class Test{
public static void main(String[] args) {
Student s = new Student();
s.setAge(18);
s.setName("张三");
System.out.println(s.getName()+":"+s.getAge()+"岁"); //张三:18岁
}
}
1.1.2构造方法在类继承中的作用
构造方法不能继承。由于子类对象要对继承自父类的成员进行初始化,因此,在创建子类对象时除了执行子类的构造方法外,还需要调用父类的构造方法。
子类调用父类构造方法时的注意事项:
- 子类可以在自己构造方法中使用关键字super来调用父类的构造方法,但super调用语句必须是子类构造方法中第一个可执行语句。
- 子类在自己定义构造方法中如果没有用super明确调用父类的哪个构造方法,则在创建对象时,系统会默认首先自动执行父类的无参构造方法,然后再执行自己定义的构造方法。
【例如】以下程序在编译时出错,原因在于父类不含无参构造方法。
public Parent{
String my;
public parent(String x){
my = x;
}
}
public class Child extends Parent{
}
【说明】在Parent类中定义了一个有参构造方法,所以系统不会自动产生无参构造方法,而在子类Child中,没有自己调用super方法,所以系统会默认自动执行父类的无参构造(相当于在子类中的第一行默认添加了:super()),但是父类中并没有无参构造,所以会出错。如果将有参构造方法注释掉,编译可通过。
鉴于上述情形,一个类在设计时如果有构造方法,最好手动提供一个无参构造方法。
【例】
import java.awt.*;
class Point{
private int x, y;
public Point(int x, int y) { //有参构造
this.x = x;
this.y = y;
}
public Point() { // 无参构造
this(0,0); //在这里this在一个构造方法中调用同类的另一个构造方法,即在无参构造中调用有参构造
}
@Override
public String toString() { //重写toString()方法
return "点:"+x+","+y;
}
}
public class Pixle extends Point{
Color c;
/*该方法也 alt+insert 可自动生成*/
public Pixle(int x, int y, Color c) { //用super调用父类的有参构造
super(x, y);
this.c = c; //在这里this来访问实例变量
}
@Override
public String toString() {
return super.toString()+"颜色:"+c; //用super访问父类方法
}
public static void main(String[] args) {
Pixle x = new Pixle(3,24,Color.black);
System.out.println(x); //点:3,24颜色:java.awt.Color[r=0,g=0,b=0]
}
}
【说明】本例中出现super关键词,super与this在使用上类似,super表示当前对象的直接父类对象的引用,通过super除了可以调用父类的构造方法外,还可以通过super引用访问父类的属性和方法。
【注意】
- 使用this查找匹配的方法时首先在本类查找,在找不到时再到其父类和祖先类查找。
- 使用super查找匹配方法时,首先到直接父类查找,若不存在,则继续到其祖先类查找
1.2多态
一般地,面向对象的多态性体现在以下两个方面:
- 方法的重载:在同一个类中定义多个方法名相同,参数列表不同(参数类型不同 ∪ 参数个数不同)的方法。
- 子类对父类方法的覆盖:子类中可对父类定义的方法重新定义,这样在子类中将覆盖来自父类的同形态方法。
1.2.1方法的重载
方法的重载就是在同一个类中定义多个方法名相同,参数列表不同(参数类型不同 ∪ 参数个数不同)的方法。
方法调用的匹配处理原则是:
- 按精确匹配原则去查找匹配方法。
- 如果精确匹配找不到,则按自动类型转换匹配原则去查找能匹配的方法。
1.2.2方法的覆盖
子类将继承父类的非私有方法,在子类中也可以对父类定义的方法重新定义,这时产生方法的覆盖。
方法覆盖的注意事项:
- 方法名、参数列表完全相同才会产生方法覆盖。返回类型通常也要一致,只有返回类型为引用类型时,允许子类方法的返回类型时父类方法返回类型的子类型。
- 方法覆盖不能改变方法的静态与非静态属性。
- 不允许子类中方法的访问修饰符比父类有更多的限制,通常应将子类中方法访问修饰与父类中的保持一致。
1.2.3访问继承的成员
如果子类中定义了与父类同名的属性,在子类中将隐藏来自父类的同名属性变量。这里也是“就近原则”,自己类中有就不会去找父类的。
【例】
class ParentShow{
int y = 8;
int m = 2;
void show(){
System.out.println("Parent.show,y="+y);
}
}
public class ChildShow extends ParentShow{
int y = 20;
int z = 1;
void show(){
System.out.println("Child.show,y="+y);
}
public static void main(String args[]){
ChildShow chid = new ChildShow();
ParentShow parent = child;//父类引用指向子类对象
System.out.println("Child.y="+child.y);
System.out.println("Parent.y="+parent.y);
child.show();
parent.show();
System.out.println("z="+child.z+",m="+child.m);
}
【运行结果】
Child.y=20
Parent.y=8
Child.show,y=20
Child.show,y=20
z=1,m=2
[说明]
- 当子类与父类有相同成员时,通过子类引用访问的成员均是子类定义的。
- 父类引用指向子类对象时,只有实例方法会是子类定义的,对象属性、静态属性、静态方法均是指父类定义的。
1.3Object类
Object类包含了所有Java类的公共属性和方法,以下给出了几个常用的方法:
- public boolean equals(Object obj):比较运算符"=="在比较两对象引用变量时,只有当两个对象引用指向统一对象时才为真。但在Object类中,equals()方法采用==运算进行比较,其他类如果没有定义equals()方法,则继承object类的equals()方法。因此,在类设计时,需要进行对象数据的比较时,一般要重写equals()方法。
- public String toString:该方法返回对象的字符串描述,其他类通常会重写该方法。
- public final Clsaa getClass():返回对象的所属类,而且利用Class类提供的getName()方法可以获取对象的类名称。
- protected void finalize():该方法在Java垃圾回收程序删除对象前自动执行。一个对象没有任何一个引用变量指向它时,Java垃圾回收成句将自动释放对象空间。
1.4访问控制修饰符
1.公共访问控制符:public
public可用于两个地方:作为类的修饰符,作为类的成员的访问修饰符。
2.默认访问控制符:defaul
默认的访问控制指在属性或方法定义前没有给出访问控制符的情形。
3.私有访问控制符:private
通常,出于系统设计的安全性考虑,将类的成员属性定义为private形式保护起来,而将类的成员方法定义为public形式对外公开,这是类封装特性的一个体现。
保护访问控制符:protected
1.5 final修饰符
可用于修饰:成员变量,非抽象类(不能与abstract同时出现),非抽象的成员方法,以及方法参数。
1.final修饰类:
表示该类不能被继承,没有子类;final类中的方法也无法被继承。
2.final修饰方法
不能被子类的方法重写,但可以被继承。final不能用于修饰构造方法。
3.final定义常量
用final标记的变量也就是常量,并且final标记的常量系统不会默认给其赋初值,所以必须定义初始化。final定义常量的初始化,可以在定义时初始化,也可以在其对应类的构造方法中初始化。
如果将引用类型的变量标记为final,那么该变量只能固定指向一个对象,不能修改,但可以改变对象内容,因为只有引用本身是final的。