1、继承的概念
继承是java面向对象编程技术的一块基石,因为它允许创建分等级层次的类。
继承就是子类继承父类的特征和行为,使得子类对象(实例)具有父类的实例域和方法,或子类从父类继承方法,使得子类具有父类相同的行为。
1.1、生活中的继承:
兔子和羊属于食草动物类,狮子和豹属于食肉动物类。
食草动物和食肉动物又是属于动物类。
所以继承需要符合的关系是:is-a,父类更通用,子类更具体。
虽然食草动物和食肉动物都是属于动物,但是两者的属性和行为上有差别,所以子类会具有父类的一般特性也会具有自身的特性。
2、 类的继承
面向对象的三大特性:
- 封装(封装细节)
- 继承
- 多态
- 继承是面向对象的重要概念,软件中的继承和现实中的继承概念是一样的
- 继承是实现软件可重用性的重要手段,如:A继承B,A就拥有了B的所有公开的特性
- java中只支持类的单继承,也就是说A只能继承B,A不能同时继承C
java中的继承使用extends 关键字,语法格式:
[修饰符] class 子类 extends 父类{
}
【代码示例】
public class ExtendsTest01 {
public static void main(String[] args) {
//如果参数比较多尽量使用setter方法,不要使用构造函数
//因为参数比较多,构造函数表达的不是很明确
Student student = new Student();
student.setId(1001);
student.setName("张三");
student.setSex(true);
student.setAddress("北京");
student.setAge(20);
student.setClassesId(10);
System.out.println("id=" + student.getId());
System.out.println("name=" + student.getName());
System.out.println("sex=" + student.getSex());
System.out.println("address=" + student.getAddress());
System.out.println("age=" + student.getAge());
System.out.println("classid=" + student.getClassesId());
System.out.println("");
System.out.println("");
Employee emp = new Employee();
emp.setId(1002);
emp.setName("李四");
emp.setSex(true);
emp.setAddress("上海");
emp.setAge(30);
emp.setWorkYear(10);
System.out.println("id=" + emp.getId());
System.out.println("name=" + emp.getName());
System.out.println("sex=" + emp.getSex());
System.out.println("address=" + emp.getAddress());
System.out.println("age=" + emp.getAge());
System.out.println("workYear=" + emp.getWorkYear());
}
}
class Student {
//学号
private int id;
//姓名
private String name;
//性别
private boolean sex;
//地址
private String address;
//年龄
private int age;
//班级编号
private int classesId;
/*
public Student(int id, String name, boolean sex, String address, int age) {
this.id = id;
this.name = name;
this.sex = sex;
this.address = address;
this.age = age;
}
*/
//设置学号
public void setId(int studentId) {
id = studentId;
}
//读取学号
public int getId() {
return id;
}
public void setName(String studentName) {
name = studentName;
}
public String getName() {
return name;
}
public void setSex(boolean studentSex) {
sex = studentSex;
}
public boolean getSex() {
return sex;
}
public void setAddress(String studentAddress) {
address = studentAddress;
}
public String getAddress() {
return address;
}
public void setAge(int studentAge) {
if (studentAge >=0 && studentAge <=120) {
age = studentAge;
}
}
public int getAge() {
return age;
}
public void setClassesId(int classesId) {
this.classesId = classesId;
}
public int getClassesId() {
return classesId;
}
}
class Employee {
//员工编号
private int id;
//姓名
private String name;
//性别
private boolean sex;
//地址
private String address;
//年龄
private int age;
//工作年限
private int workYear;
//设置学号
public void setId(int studentId) {
id = studentId;
}
//读取学号
public int getId() {
return id;
}
public void setName(String studentName) {
name = studentName;
}
public String getName() {
return name;
}
public void setSex(boolean studentSex) {
sex = studentSex;
}
public boolean getSex() {
return sex;
}
public void setAddress(String studentAddress) {
address = studentAddress;
}
public String getAddress() {
return address;
}
public void setAge(int studentAge) {
if (studentAge >=0 && studentAge <=120) {
age = studentAge;
}
}
public int getAge() {
return age;
}
public void setWorkYear(int workYear) {
this.workYear = workYear;
}
public int getWorkYear() {
return workYear;
}
}
以上输出是完全正确的,但程序上存在一些冗余,因为Student和Employee都重复出现了id,name,address,sex,age属性,而Student和Employee其实都是Person,所以应该具有person的相关属性,所以完全可以抽取出一个Person类出来,让Student和Employee继承它,这样我们的冗余代码就会减少
【代码示例】,提取Person类,让Student和Employee继承Person
public class ExtendsTest02 {
public static void main(String[] args) {
Student student = new Student();
student.setId(1001);
student.setName("张三");
student.setSex(true);
student.setAddress("北京");
student.setAge(20);
student.setClassesId(10);
System.out.println("id=" + student.getId());
System.out.println("name=" + student.getName());
System.out.println("sex=" + student.getSex());
System.out.println("address=" + student.getAddress());
System.out.println("age=" + student.getAge());
System.out.println("classid=" + student.getClassesId());
System.out.println("");
System.out.println("");
Employee emp = new Employee();
emp.setId(1002);
emp.setName("李四");
emp.setSex(true);
emp.setAddress("上海");
emp.setAge(30);
emp.setWorkYear(10);
System.out.println("id=" + emp.getId());
System.out.println("name=" + emp.getName());
System.out.println("sex=" + emp.getSex());
System.out.println("address=" + emp.getAddress());
System.out.println("age=" + emp.getAge());
System.out.println("workYear=" + emp.getWorkYear());
}
}
class Person {
//姓名
private String name;
//性别
private boolean sex;
//地址
private String address;
//年龄
private int age;
//设置学号
public void setId(int studentId) {
id = studentId;
}
//读取学号
public int getId() {
return id;
}
public void setName(String studentName) {
name = studentName;
}
public String getName() {
return name;
}
public void setSex(boolean studentSex) {
sex = studentSex;
}
public boolean getSex() {
return sex;
}
public void setAddress(String studentAddress) {
address = studentAddress;
}
public String getAddress() {
return address;
}
public void setAge(int studentAge) {
if (studentAge >=0 && studentAge <=120) {
age = studentAge;
}
}
public int getAge() {
return age;
}
}
class Student extends Person {
//学号
private int sid;
//班级编号
private int classesId;
public void setClassesId(int classesId) {
this.classesId = classesId;
}
public int getClassesId() {
return classesId;
}
}
class Employee extends Person {
//编号
private int eno;
//工作年限
private int workYear;
public void setWorkYear(int workYear) {
this.workYear = workYear;
}
public int getWorkYear() {
return workYear;
}
}
运行结果和前面的一样,先从代码数量上来看,比以前少多了,没有重复了,软件设计有一个原则“重复的代码最好不要出现两次或多次”,如果出现两次以上相同的代码,那么就不好维护了,如果要改的话,那么多处都要改,给维护带来不变,而从我们的这个示例,大家看到采用继承可以达到重用性,把父类中的所有属性都继承下来了。
注:继承是对象级别的继承,将父类对象属性、方法继承过来
静态信息是存储在方法区,可以直接通过类名调用,在对象之前创建,所以不是对象级别的,更不能被继承
3、 方法的覆盖(Override)
首先看一下方法重载(Overload),回顾方法重载的条件:
- 方法名称相同
- 方法参数类型、个数、顺序至少有一个不同
- 方法的返回类型可以不同,因为方法重载和返回类型没有任何关系
- 方法的修饰符可以不同,因为方法重载和修饰符没有任何关系
- 方法重载只出现在同一个类中
方法的覆盖(Override)的条件:
- 必须要有继承关系
- 覆盖只能出现在子类中,如果没有继承关系,不存在覆盖,只存在重载
- 在子类中被覆盖的方法,必须和父类中的方法完全一样,也就是方法名,返回类型、参数列表,完全一样
- 子类方法的访问权限不能小于父类方法的访问权限
- 子类方法不能抛出比父类方法更多的异常,但可以抛出父类方法异常的子异常
- 父类的静态方法不能被子类覆盖
- 父类的私有方法不能覆盖
- 覆盖是针对成员方法,而非属性
为什么需要覆盖?
就是要改变父类的行为。
1、对成员方法覆盖
【代码示例】,继承父类方法,不覆盖
public class OverrideTest01 {
public static void main(String[] args) {
Student student = new Student();
student.setId(1001);
student.setName("张三");
student.setSex(true);
student.setAddress("北京");
student.setAge(20);
student.setClassesId(10);
student.printInfo();
System.out.println("");
Employee emp = new Employee();
emp.setId(1002);
emp.setName("李四");
emp.setSex(true);
emp.setAddress("上海");
emp.setAge(30);
emp.setWorkYear(10);
emp.printInfo();
}
}
class Person {
//学号
private int id;
//姓名
private String name;
//性别
private boolean sex;
//地址
private String address;
//年龄
private int age;
public void printInfo() {
System.out.println("id=" + id + ", name=" + name + ",sex=" + sex + ", address=" + address + ", age=" + age);
}
//设置学号
public void setId(int studentId) {
id = studentId;
}
//读取学号
public int getId() {
return id;
}
public void setName(String studentName) {
name = studentName;
}
public String getName() {
return name;
}
public void setSex(boolean studentSex) {
sex = studentSex;
}
public boolean getSex() {
return sex;
}
public void setAddress(String studentAddress) {
address = studentAddress;
}
public String getAddress() {
return address;
}
public void setAge(int studentAge) {
if (studentAge >=0 && studentAge <=120) {
age = studentAge;
}
}
public int getAge() {
return age;
}
}
class Student extends Person {
//班级编号
private int classesId;
public void setClassesId(int classesId) {
this.classesId = classesId;
}
public int getClassesId() {
return classesId;
}
}
class Employee extends Person {
//工作年限
private int workYear;
public void setWorkYear(int workYear) {
this.workYear = workYear;
}
public int getWorkYear() {
return workYear;
}
}
【代码示例】,继承父类方法,覆盖父类中的方法(改变父类的行为)
public class OverrideTest02 {
public static void main(String[] args) {
Student student = new Student();
student.setId(1001);
student.setName("张三");
student.setSex(true);
student.setAddress("北京");
student.setAge(20);
student.setClassesId(10);
student.printInfo();
System.out.println("");
Employee emp = new Employee();
emp.setId(1002);
emp.setName("李四");
emp.setSex(true);
emp.setAddress("上海");
emp.setAge(30);
emp.setWorkYear(10);
emp.printInfo();
}
}
class Person {
//学号
private int id;
//姓名
private String name;
//性别
private boolean sex;
//地址
private String address;
//年龄
private int age;
public void printInfo() {
System.out.println("id=" + id + ", name=" + name + ",sex=" + sex + ", address=" + address + ", age=" + age);
}
//设置学号
public void setId(int studentId) {
id = studentId;
}
//读取学号
public int getId() {
return id;
}
public void setName(String studentName) {
name = studentName;
}
public String getName() {
return name;
}
public void setSex(boolean studentSex) {
sex = studentSex;
}
public boolean getSex() {
return sex;
}
public void setAddress(String studentAddress) {
address = studentAddress;
}
public String getAddress() {
return address;
}
public void setAge(int studentAge) {
if (studentAge >=0 && studentAge <=120) {
age = studentAge;
}
}
public int getAge() {
return age;
}
}
class Student extends Person {
//班级编号
private int classesId;
public void setClassesId(int classesId) {
this.classesId = classesId;
}
public int getClassesId() {
return classesId;
}
public void printInfo() {
System.out.println("id=" + getId() + ", name=" + getName() + ",sex=" + getSex() + ", address=" + getAddress() + ", age=" + getAge() + ",classesid=" + classesId);
}
}
class Employee extends Person {
//工作年限
private int workYear;
public void setWorkYear(int workYear) {
this.workYear = workYear;
}
public int getWorkYear() {
return workYear;
}
public void printInfo() {
System.out.println("id=" + getId() + ", name=" + getName() + ",sex=" + getSex() + ", address=" + getAddress() + ", age=" + getAge() + ", workYear=" + workYear);
}
}
以上子类对父类的方法进行了覆盖,改变了父类的行为,当我们new子类的时候,它不会再调用父类的方法了,而直接调用子类的方法,所以我们就完成了对父类行为的扩展。
【代码示例】,改善以上示例
public class OverrideTest03 {
public static void main(String[] args) {
//Student student = new Student();
//此种写法是错误的,Person不是Student
//Student person_student = new Person();
//此种写法是正确的,Student是Person
Person person_student = new Student();
person_student.setId(1001);
person_student.setName("张三");
person_student.setSex(true);
person_student.setAddress("北京");
person_student.setAge(20);
//编译出错,因为Person看不到子类Student的属性
//person_student.setClassesId(10);
person_student.printInfo();
System.out.println("");
//Employee person_emp = new Employee();
Person person_emp = new Employee();
person_emp.setId(1002);
person_emp.setName("李四");
person_emp.setSex(true);
person_emp.setAddress("上海");
person_emp.setAge(30);
//编译出错,因为Person看不到子类Employee的属性
//person_emp.setWorkYear(10);
person_emp.printInfo();
}
}
class Person {
//学号
private int id;
//姓名
private String name;
//性别
private boolean sex;
//地址
private String address;
//年龄
private int age;
public void printInfo() {
System.out.println("id=" + id + ", name=" + name + ",sex=" + sex + ", address=" + address + ", age=" + age);
}
//设置学号
public void setId(int studentId) {
id = studentId;
}
//读取学号
public int getId() {
return id;
}
public void setName(String studentName) {
name = studentName;
}
public String getName() {
return name;
}
public void setSex(boolean studentSex) {
sex = studentSex;
}
public boolean getSex() {
return sex;
}
public void setAddress(String studentAddress) {
address = studentAddress;
}
public String getAddress() {
return address;
}
public void setAge(int studentAge) {
if (studentAge >=0 && studentAge <=120) {
age = studentAge;
}
}
public int getAge() {
return age;
}
}
class Student extends Person {
//班级编号
private int classesId;
public void setClassesId(int classesId) {
this.classesId = classesId;
}
public int getClassesId() {
return classesId;
}
public void printInfo() {
System.out.println("id=" + getId() + ", name=" + getName() + ",sex=" + getSex() + ", address=" + getAddress() + ", age=" + getAge() + ",classesid=" + classesId);
}
}
class Employee extends Person {
//工作年限
private int workYear;
public void setWorkYear(int workYear) {
this.workYear = workYear;
}
public int getWorkYear() {
return workYear;
}
public void printInfo() {
System.out.println("id=" + getId() + ", name=" + getName() + ",sex=" + getSex() + ", address=" + getAddress() + ", age=" + getAge() + ", workYear=" + workYear);
}
}
【代码示例】,改善以上示例
public class OverrideTest04 {
public static void main(String[] args) {
Person person_student = new Student();
person_student.setId(1001);
person_student.setName("张三");
person_student.setSex(true);
person_student.setAddress("北京");
person_student.setAge(20);
print(person_student);
Person person_emp = new Employee();
person_emp.setId(1002);
person_emp.setName("李四");
person_emp.setSex(true);
person_emp.setAddress("上海");
person_emp.setAge(30);
print(person_emp);
Person person = new Person();
person.setId(1003);
person.setName("王五");
person.setSex(true);
print(person);
}
private static void print(Person person) {
person.printInfo();
}
}
class Person {
//学号
private int id;
//姓名
private String name;
//性别
private boolean sex;
//地址
private String address;
//年龄
private int age;
public void printInfo() {
System.out.println("id=" + id + ", name=" + name + ",sex=" + sex + ", address=" + address + ", age=" + age);
}
//设置学号
public void setId(int studentId) {
id = studentId;
}
//读取学号
public int getId() {
return id;
}
public void setName(String studentName) {
name = studentName;
}
public String getName() {
return name;
}
public void setSex(boolean studentSex) {
sex = studentSex;
}
public boolean getSex() {
return sex;
}
public void setAddress(String studentAddress) {
address = studentAddress;
}
public String getAddress() {
return address;
}
public void setAge(int studentAge) {
if (studentAge >=0 && studentAge <=120) {
age = studentAge;
}
}
public int getAge() {
return age;
}
}
class Student extends Person {
//班级编号
private int classesId;
public void setClassesId(int classesId) {
this.classesId = classesId;
}
public int getClassesId() {
return classesId;
}
public void printInfo() {
System.out.println("id=" + getId() + ", name=" + getName() + ",sex=" + getSex() + ", address=" + getAddress() + ", age=" + getAge() + ",classesid=" + classesId);
}
}
class Employee extends Person {
//工作年限
private int workYear;
public void setWorkYear(int workYear) {
this.workYear = workYear;
}
public int getWorkYear() {
return workYear;
}
public void printInfo() {
System.out.println("id=" + getId() + ", name=" + getName() + ",sex=" + getSex() + ", address=" + getAddress() + ", age=" + getAge() + ", workYear=" + workYear);
}
}
多态其实就是多种状态,overload(重载)是多态的一种,属于编译期绑定,也就是静态绑定(前期绑定),override是运行期间绑定(后期绑定)。
多态存在的条件:
- 有继承
- 有覆盖
- 父类指向子类的引用
2、对静态方法覆盖
【代码示例】、
public class OverrideTest05 {
public static void main(String[] args) {
Person person_student = new Student();
person_student.setId(1001);
person_student.setName("张三");
person_student.setSex(true);
person_student.setAddress("北京");
person_student.setAge(20);
print(person_student);
Person person_emp = new Employee();
person_emp.setId(1002);
person_emp.setName("李四");
person_emp.setSex(true);
person_emp.setAddress("上海");
person_emp.setAge(30);
print(person_emp);
}
private static void print(Person person) {
person.printInfo();
}
}
class Person {
//学号
private int id;
//姓名
private String name;
//性别
private boolean sex;
//地址
private String address;
//年龄
private int age;
public static void printInfo() {
System.out.println("------------Person--------------");
}
//设置学号
public void setId(int studentId) {
id = studentId;
}
//读取学号
public int getId() {
return id;
}
public void setName(String studentName) {
name = studentName;
}
public String getName() {
return name;
}
public void setSex(boolean studentSex) {
sex = studentSex;
}
public boolean getSex() {
return sex;
}
public void setAddress(String studentAddress) {
address = studentAddress;
}
public String getAddress() {
return address;
}
public void setAge(int studentAge) {
if (studentAge >=0 && studentAge <=120) {
age = studentAge;
}
}
public int getAge() {
return age;
}
}
class Student extends Person {
//班级编号
private int classesId;
public void setClassesId(int classesId) {
this.classesId = classesId;
}
public int getClassesId() {
return classesId;
}
public static void printInfo() {
System.out.println("------------Student------------");
}
}
class Employee extends Person {
//工作年限
private int workYear;
public void setWorkYear(int workYear) {
this.workYear = workYear;
}
public int getWorkYear() {
return workYear;
}
public static void printInfo() {
System.out.println("------------Employee------------");
}
}
从上面的输出可以看到,静态方法不存在多态的概念,多态和成员方法相关,静态方法只属于某一个类,声明的是那个一个类就调用的是哪一个类的静态方法和子类没有关系,不像覆盖了成员方法,new谁调谁,为什么覆盖成员方法可以构成多态(多种状态),主要是运行期的动态绑定(动态绑定构成多态),静态绑定的含义是在编译成class文件(字节码)的时候已经确定该调用哪个方法。
4、 super关键字
super关键字的作用:
- 调用父类的构造方法
- 调用父类的成员方法
需要注意:super只能应用在成员方法和构造方法中,不能应用在静态方法中(和this是一样的,代表父类对象),如果在构造方法中使用必须放在第一行
为什么会有super关键字?
- 因为子类必须要调用父类的构造方法,先把父类构造完成,因为子类依赖于父类,没有父,也就没有子
- 有时需要在子类中显示的调用父类的成员方法
那么我们以前为什么没有看到super,而且我们也有继承,如:Student继承了Person?
- 因为子类中我们没有显示的调用构造方法,那么他会默认调用父类的无参构造方法,此种情况下如果父类中没有无参构造方法,那么编译时将会失败
1、调用默认构造方法
public class SuperTest01 {
public static void main(String[] args) {
Person student = new Student();
}
}
class Person {
//学号
private int id;
//姓名
private String name;
//性别
private boolean sex;
//地址
private String address;
//年龄
private int age;
public Person() {
//System.out.println(this);
System.out.println("----------Person-----------");
}
//设置学号
public void setId(int studentId) {
id = studentId;
}
//读取学号
public int getId() {
return id;
}
public void setName(String studentName) {
name = studentName;
}
public String getName() {
return name;
}
public void setSex(boolean studentSex) {
sex = studentSex;
}
public boolean getSex() {
return sex;
}
public void setAddress(String studentAddress) {
address = studentAddress;
}
public String getAddress() {
return address;
}
public void setAge(int studentAge) {
if (studentAge >=0 && studentAge <=120) {
age = studentAge;
}
}
public int getAge() {
return age;
}
}
class Student extends Person {
//班级编号
private int classesId;
public Student() {
//System.out.println(this);
//显示调用父类的构造方法
//调用父类的无参的构造函数
//super();
System.out.println("--------Student----------");
//编译错误,必须将super放到构造函数的第一语句
//必须先创建父类,才能创建子类
//super();
}
public void setClassesId(int classesId) {
this.classesId = classesId;
}
public int getClassesId() {
return classesId;
}
}
关于构造方法的执行顺序,先执行父类的再执行子类的,必须完成父类的所有初始化,才能创建子类
2、调用带参数的构造方法
public class SuperTest02 {
public static void main(String[] args) {
/*
Person person_student = new Student();
person_student.setId(1001);
person_student.setName("张三");
person_student.setSex(true);
person_student.setAddress("北京");
person_student.setAge(20);
*/
//编译出错,因为Person看不到子类Student的属性
//person_student.setClassesId(10);
/*
person_student.printInfo();
System.out.println("");
Person person_emp = new Employee();
person_emp.setId(1002);
person_emp.setName("李四");
person_emp.setSex(true);
person_emp.setAddress("上海");
person_emp.setAge(30);
*/
//编译出错,因为Person看不到子类Employee的属性
//person_emp.setWorkYear(10);
//person_emp.printInfo();
Person person_student = new Student(1001, "张三", true, "北京", 20, 10);
person_student.printInfo();
}
}
class Person {
//学号
private int id;
//姓名
private String name;
//性别
private boolean sex;
//地址
private String address;
//年龄
private int age;
public Person() {
System.out.println("--------------Person-------------");
}
public Person(int id, String name, boolean sex, String address, int age) {
this.id = id;
this.name = name;
this.sex = sex;
this.address = address;
this.age= age;
}
public void printInfo() {
System.out.println("id=" + id + ", name=" + name + ",sex=" + sex + ", address=" + address + ", age=" + age);
}
//设置学号
public void setId(int studentId) {
id = studentId;
}
//读取学号
public int getId() {
return id;
}
public void setName(String studentName) {
name = studentName;
}
public String getName() {
return name;
}
public void setSex(boolean studentSex) {
sex = studentSex;
}
public boolean getSex() {
return sex;
}
public void setAddress(String studentAddress) {
address = studentAddress;
}
public String getAddress() {
return address;
}
public void setAge(int studentAge) {
if (studentAge >=0 && studentAge <=120) {
age = studentAge;
}
}
public int getAge() {
return age;
}
}
class Student extends Person {
//班级编号
private int classesId;
public Student(int id, String name, boolean sex, String address, int age, int classesId) {
/*
this.id = id;
this.name = name;
this.sex = sex;
this.address = address;
this.age= age;
this.classesId = id;
*/
/*
setId(id);
setName(name);
setSex(sex);
setAddress(address);
setAge(age);
this.classesId = classesId;
*/
//手动调用调用带参数的构造函数
super(id, name, sex, address, age);
this.classesId = classesId;
}
public void setClassesId(int classesId) {
this.classesId = classesId;
}
public int getClassesId() {
return classesId;
}
public void printInfo() {
System.out.println("id=" + getId() + ", name=" + getName() + ",sex=" + getSex() + ", address=" + getAddress() + ", age=" + getAge() + ",classesid=" + classesId);
}
}
class Employee extends Person {
//工作年限
private int workYear;
public void setWorkYear(int workYear) {
this.workYear = workYear;
}
public int getWorkYear() {
return workYear;
}
public void printInfo() {
System.out.println("id=" + getId() + ", name=" + getName() + ",sex=" + getSex() + ", address=" + getAddress() + ", age=" + getAge() + ", workYear=" + workYear);
}
}
3、采用super调用父类的方法
public class SuperTest03 {
public static void main(String[] args) {
Person person_student = new Student();
person_student.setId(1001);
person_student.setName("张三");
person_student.setSex(true);
person_student.setAddress("北京");
person_student.setAge(20);
print(person_student);
Person person_emp = new Employee();
person_emp.setId(1002);
person_emp.setName("李四");
person_emp.setSex(true);
person_emp.setAddress("上海");
person_emp.setAge(30);
print(person_emp);
}
private static void print(Person person) {
person.printInfo();
}
}
class Person {
//学号
private int id;
//姓名
private String name;
//性别
private boolean sex;
//地址
private String address;
//年龄
private int age;
public void printInfo() {
System.out.println("id=" + id + ", name=" + name + ",sex=" + sex + ", address=" + address + ", age=" + age);
}
//设置学号
public void setId(int studentId) {
id = studentId;
}
//读取学号
public int getId() {
return id;
}
public void setName(String studentName) {
name = studentName;
}
public String getName() {
return name;
}
public void setSex(boolean studentSex) {
sex = studentSex;
}
public boolean getSex() {
return sex;
}
public void setAddress(String studentAddress) {
address = studentAddress;
}
public String getAddress() {
return address;
}
public void setAge(int studentAge) {
if (studentAge >=0 && studentAge <=120) {
age = studentAge;
}
}
public int getAge() {
return age;
}
}
class Student extends Person {
//班级编号
private int classesId;
public void setClassesId(int classesId) {
this.classesId = classesId;
}
public int getClassesId() {
return classesId;
}
public void printInfo() {
//System.out.println("id=" + getId() + ", name=" + getName() + ",sex=" + getSex() + ", address=" + getAddress() + ", age=" + getAge() + ",classesid=" + classesId);
//采用super调用父类的方法
super.printInfo();
System.out.println("classesId=" + classesId);
}
}
class Employee extends Person {
//工作年限
private int workYear;
public void setWorkYear(int workYear) {
this.workYear = workYear;
}
public int getWorkYear() {
return workYear;
}
public void printInfo() {
//System.out.println("id=" + getId() + ", name=" + getName() + ",sex=" + getSex() + ", address=" + getAddress() + ", age=" + getAge() + ", workYear=" + workYear);
System.out.println("workYear=" + workYear);
//采用super调用父类的方法
super.printInfo();
}
}
5、 final关键字
final表示不可改变的含义
- 采用final修饰的类不能被继承
- 采用final修饰的方法不能被覆盖
- 采用final修饰的变量不能被修改
- final修饰的变量必须显示初始化
- 如果修饰的引用,那么这个引用只能指向一个对象,也就是说这个引用不能再次赋值,但被指向的对象是可以修改的
- 构造方法不能被final修饰
会影响JAVA类的初始化:final定义的静态常量调用时不会执行java的类初始化方法,也就是说不会执行static代码块等相关语句,这是由java虚拟机规定的。我们不需要了解的很深,有个概念就可以了。
1、采用final修饰的类不能被继承
```java public class FinalTest01 {
public static void main(String[] args) {
}
}
final class A1 { public void test1() {
}
}
//不能继承A1,因为A1采用final修饰了 class B1 extends A1 {
public void test2() {
}
}
<a name="poRfD"></a>
### **2、采用final修饰的方法不能被覆盖**
```java
public class FinalTest02 {
public static void main(String[] args) {
}
}
class A1 {
public final void test1() {
}
}
class B1 extends A1 {
//覆盖父类的方法,改变其行为
//因为父类的方法是final修饰的,所以不能覆盖
public void test1() {
}
public void test2() {
}
}
3、采用final修饰的变量(基本类型)不能被修改
public class FinalTest03 {
private static final long CARD_NO = 878778878787878L;
public static void main(String[] args) {
//不能进行修改,因为CARD_NO采用final修改了
CARD_NO = 99999999999999L;
}
}
4、final修饰的变量必须显示初始化
public class FinalTest04 {
//如果是final修饰的变量必须初始化
private static final long CARD_NO = 0L;
public static void main(String[] args) {
int i;
//局部变量必须初始化
//如果不使用可以不初始化
System.out.println(i);
}
}
5、如果修饰的引用,那么这个引用只能指向一个对象,也就是说这个引用不能再次赋值,但被指向的对象是可以修改的
public class FinalTest05 {
public static void main(String[] args) {
Person p1 = new Person();
//可以赋值
p1.name = "张三";
System.out.println(p1.name);
final Person p2 = new Person();
p2.name = "李四";
System.out.println(p2.name);
//不能编译通过
//p2采用final修饰,主要限制了p2指向堆区中的地址不能修改(也就是p2只能指向一个对象)
//p2指向的对象的属性是可以修改的
p2 = new Person();
}
}
class Person {
String name;
}