上一篇文章:基本数据类型的类封装、数组作为方法的参数以及从方法中返回数组、对象数组、文档生成器
回顾面向对象三个特点
-
封装性:
把一类事物共有的数据和对这些数据的操作(方法method)封装到一个类(class)里面。方法(method)是特殊的函数(function)
-
继承:
子类可以继承父类的一些属性,同时也可以增添子类独有的属性
-
多态:
两种多态,一是多种操作具有相同的名字,即操作名称的多态;另一种是和继承有关的多态,即一个操作被不同类型对象调用时可能产生不同的行为
回顾访问权限
- public 修饰的变量或方法叫做 共有变量 或 共有方法
- protected 修饰的变量或方法叫做 受保护的变量 或 受保护的方法
- private 修饰的变量或方法叫做 私有变量 或 私有方法
- 没有用 public 、protected 和 private 修饰的变量或方法叫做 友好变量 或 友好方法
具体访问权限请参考前面的文章
子类继承父类
子类的定义格式:
class 子类名 extends 父类名 {
...
}
子类会继承父类的一些属性,具体的继承规则如下:
当子类和父类在同一个包中时:
- 子类会继承父类中的 共有变量、共有方法、受保护的变量、受保护的方法、友好变量、友好方法;父类中只有 私有变量 和 私有方法 不会被子类继承。
当子类和父类不在同一个包中时:
- 父类中只有用 public 修饰的变量和方法才会被子类继承
class People { //一个people类
String name; //友好变量
float height; //友好变量
float weight; //友好变量
void speak(){ //友好方法
System.out.println("我的名字是"+name);
System.out.println("我的身高是"+height+"米");
System.out.println("我的体重是"+weight+"公斤");
}
}
class Student extends People { //Student类继承了People类
String xuehao; //Student类增添了一个属于自己的成员变量xuehao
//Student类继承了people类,会把People类中所有的友好变量继承过来
//同时也会把People类中的友好方法继承过来
void studentspeak(){ //Student类增加自己的方法
System.out.println("我的学号是"+xuehao);
}
}
class UniverStudent extends Student { //UniverStudent类继承了Student类
void UstuSpeak(){
System.out.println("我的名字是"+name);
System.out.println("我的学号是"+xuehao);
}
}
public class Example {
public static void main(String args[]){
People zhang = new People();
zhang.name = "张三";
zhang.height = 1.70f;
zhang.weight = 71.2f;
Student li = new Student();
li.name = "李四";
li.xuehao = "123456789";
li.height = 1.76f;
li.weight = 68.2f;
UniverStudent wang = new UniverStudent();
wang.name = "王二";
wang.xuehao = "66669999";
System.out.println("社会青年张三说:");
zhang.speak();
System.out.println(); //换行
System.out.println("在校学生李四说:");
li.speak(); //调用继承People类中的方法speak()
li.studentspeak(); //调用Student类自己的方法studentspeak()
System.out.println();
System.out.println("大学生自王二说:");
wang.UstuSpeak();
}
}
注意:
- Java中一个子类只能有一个父类,但一个父类可以有多个子类。
- 可以连续多代继承,即D类继承C类,C类继承B类,B类继承A类。
- Java中所有的类都一个祖先类Object类,Object类在
java.lang
包中,所有的类都是Object类的后代。
下面演示一个复杂的继承:(注意里面有一个微妙的细节,请仔细阅读代码及其详细注释)
//文件路径: C:\j\jack
//源文件People.java
package jack; //People类在jack包中
public class People {
protected String a; //受保护的变量
protected void speak(){ //受保护的方法
System.out.println(a);
}
}
//文件路径: C:\j\jack1
//源文件Student.java
package jack1; //Student类在jack1包中
import jack.People; //导入jack包中的People类
public class Student extends People { //继承People类
String name;
}
//这种情况下People类中的protected修饰的成员变量和方法都不会被继承的
//文件路径: C:\j\jack
//源文件UniverStu.java
package jack; //UniverStu类在jack包中,与People类同包
import jack1.Student; //导入jack1包中的Student类
public class UniverStu extends Student { //继承Student类
String xuehao;
}
//这种情况下UniverStu类会继承People类中的protected修饰的成员变量和方法
//UniverStu类没有继承Student类中的name成员变量,因为这两个类不在同一包中,name没有用public修饰
//People类和UniverStu类在同一包中,People是UniverStu的“爷爷类”,所以继承了protected修饰的变量和方法
//文件路径: C:\j\jack
//源文件Example.java
package jack; //Example类在jack包中
public class Example {
public static void main(String args[]){
UniverStu zhang = new UniverStu(); //定义了一个UniverStu类的对象zhang
zhang.a = "haha"; //变量a是继承People类的
zhang.speak(); //speak()方法是继承People类的
}
}
编译及其运行如下:
创建子类对象时的内存模型:在使用子类作为模板创建对象时,无论子类有没有继承父类中的成员变量,都会为其分配内存空间,包括私有变量在内。既然子类没有访问父类中private私有变量的权限,为什么还要为他们分配内存空间呢?因为子类会继承父类的中的一些方法,而这些方法可能会用到私有变量,所以在使用子类创建对象时,也会为私有变量分配内存空间。
instanceof运算符
使用格式 对象 instanceof 类
,作用:判断instanceof左边的对象是否为右边类创建的。是 返回true,不是 返回false
class People {
String name;
}
class Student extends People {
String xuehao;
}
class Example {
public static void main(String args[]){
People zhang = new People();
Student li = new Student();
System.out.println(li instanceof Student);
System.out.println(li instanceof People);
System.out.println(zhang instanceof Student);
System.out.println(zhang instanceof People);
}
}
运行结果如下:
li
即是Student类,也是People类,因为Student类继承的People类,但是zhang
只能是People类,而不是Student类。