目标
- (1)理解继承与派生、多态的概念及它们之间的关系;
- (2)掌握子类与父类的定义与实现方法,并学会成员变量隐藏及重写父类方法;
- (3)理解关键字super、final的作用和用法并在实践中灵活运用;
- (4)理解抽象类与抽象方法的使用场景,掌握它们的用法.
面向对象编程的三大特征 :封装,继承,多态
封装
封装就是把抽象出来的数据和对数据的操作封装在类中,数据被保护在内部,又设置了多种访问权限,程序的其它部分只有通过被授权的操作(成员方法),才能对数据进行操作。
比如:电视机的开关:对音量,颜色,频道的控制是公开的, 谁都可以操作,但是对机箱后盖,主机板的操作却不是 公开的,一般是由专业维修人员来玩。
/*
* 访问控制权:public, private, protected,以及默认情况(友好变量、友好成员)
*/
public class demo5{
public static void main(String []args){
//创建一个职员
Clerk clerk1=new Clerk("小花",24,4567.6f);
//在Clerk的类外不能访问其私有成员,比如:
//clerk1.age=30; 错误
System.out.println("名字是"+clerk1.name+"薪水 "+clerk1.getSal());
//试试哪几个变量可以调用
Person p=new Person();
p.addr = "1111";
p.name = "123";
p.telephone = "1234";
}
}
//职员
class Clerk{
public String name;
//private私有的,public公有的
private int age;
private float salary;
public Clerk(String name,int age,float sal){
this.name=name;
this.age=age;
this.salary=sal;
}
//通过一个成员方法去控制和访问私有的属性
public float getSal(){
return this.salary;
}
}
//人类
class Person{
public String name;
protected String addr;
String telephone;
private int age;
//一些方法
}
继承
继承可以解决代码复用,让我们的编程思想更加接近人类思维,当多个类存在相同的属性(变量)和方法时,可以从这些类中抽象出父类(也叫超类),在父类中定义这些相同的属性和方法,所有子类不需要重新定义这些属性和方法,只需要通过extends语句来继承父类:
class 子类 extends 父类{
//
}
继承注意事项
- 子类最多只能继承一个父类(指直接继承)
- java中所有类都是Object类的子类
- 多查jdk帮助文档
- 搜索引擎学习
继承时,父类和子类的构造方法如何运行?
- 继承发生时,先运行父类的构造方法,再运行子类的构造方法。
- 如果程序员没有为父类写构造方法,则运行父类默认的构造方法
- 如果要调用父类带参数的构造方法,则在子类的构造方法中必须显示地告诉调用父类的某个带参数的构造方法,通过super关键字,这条语句还必须出现在构造方法的第一句。
super关键字使用
package demo6_1;
//功能:说明继承的重要性
//继承时,父类和子类的构造方法如何运行?
//super关键字:使用super访问父类的构造方法
//注意:静态方法(类方法)中不能使用super关键字
public class Constructor1 {
public static void main(String[] args) {
Pupil p1=new Pupil();
p1.printName();
p1.printFee();
Pupil p2=new Pupil("明明",25,500);
p2.printName();
p2.printFee();
Pupil p3=new Pupil("小花",20);
p3.printName();
p3.printAge();
}
}
class Student{
//定义成员属性
public String name; //公有的
protected int age; //受保护的
float fee; //默认的
private String job;//私有将不被继承
public Student(){
System.out.println("测试: 父类构造方法1在运行");
}
public Student(String name,int age){
this.name=name;
this.age=age;
System.out.println("测试: 父类构造方法2在运行");
}
public void setJob(String job){
this.job=job;
}
public void printName(){
System.out.println("名字: "+this.name);
}
public void printAge(){
System.out.println("年龄: "+this.age);
}
public void printFee(){
System.out.println("学费: "+this.fee);
}
}
//小学生类
class Pupil extends Student{
public Pupil(){
System.out.println("测试: 子类构造方法1在运行");
}
public Pupil(String name,int age,float fee){
super(name, age); //用super()访问父类的构造方法 //可以只super()一部分,其余使用this关键字
//this.fee=fee;
System.out.println("测试: 子类构造方法2在运行");
}
public Pupil(String name, int age){
this.name=name;
this.age=age;
System.out.println("测试: 子类构造方法3在运行");
}
}
子类重写父类方法
简单的说:方法重写就是子类有一个方法,和父类的某个方法的名称、返回类型、参数一样,那么我们就说子类的这个方法重写了父类的那个方法。
注意事项:
- 子类的方法的返回类型,参数,方法名称,要和父类的返回类型,参数,方法名称完全一样,否则编译出错。
- 子类方法不能缩小父类方法的访问权限。
- 继承时,子类如果存在和父类同名的成员变量,或者子类重写父类存在的方法,这时候称为子类隐藏了父类中的成员(包括成员变量和成员方法),如果要在子类中访问父类中被隐藏的成员,可以通过如下方法实现:super.父类中被隐藏的成员;
- 静态方法中不能引用super关键字。
package demo6_2;
/*
* (1)继承时,父类和子类的构造方法如何运行?
* 使用super访问父类
* (2)方法覆盖
* super.方法名()访问从父类继承的方法
*/
public class Constructor2 {
public static void main(String[] args) {
// TODO Auto-generated method stub
Student1 stu=new Student1("Jan",10031006);
Undergraduate und=new Undergraduate("Max",10031006,5600,"助教");
stu.print();
und.print();
}
}
//父类Student
class Student1{
public String name; //姓名
protected int number; //学号
static float fee; //学费
public Student1(String name,int number){
this.name=name;
this.number=number;
}
protected void setFee(float fee){
this.fee=fee;
}
public void print(){
System.out.println("姓名:"+name+" 学号:"+number+" 学费:"+fee);
}
}
//子类Pupil
class Pupil1 extends Student1{
public Pupil1(String name,int number){
super(name, number);
}
}
class Undergraduate extends Student1{
public String job; //工作
public Undergraduate(String name,int number, float fee,String job){
super(name,number);
this.fee=fee;
this.job=job;
}
//方法重写
public void print(){
//super.print(); //调用父类的print()方法
System.out.println("姓名:"+name+" 学号:"+number+" 学费:"+fee+" 兼职:"+job);
}
}
方法重载
简单的说:方法重载就是在类的同一种功能的多种实现方式,到底采用哪种方式,取决于调用者给出的参数。
注意事项:
- 方法名相同
- 方法的参数类型,个数,顺序至少有一项不同(与方法重写不同的地方)
- 方法返回类型可以不同 (只是返回类型不一样,不能构成重载)
- 方法的修饰符可以不同(只是控制访问修饰符不同,不能构成重载)
final关键字
final关键字可以修饰类、成员变量和方法中的局部变量。
- 可以使用final将类声明为final类。final类不能被继承,即不能有子类。
- 如果用final修饰父类中的一个方法,那么这个方法不允许子类重写。
- 如果成员变量或局部变量被修饰为final的,就是常量。
final的作用?
final和static的区别?
多态
public class demo7 {
public static void main(String[] args) {
//非多态演示
System.out.println("非多态演示:");
Cat cat=new Cat();
cat.speak();
Dog dog=new Dog();
dog.speak();
System.out.println();
//多态演示
System.out.println("多态演示:");
Animal an=new Cat();
an.speak();
an=new Dog();
an.speak();
System.out.println();
//多重多态演示
System.out.println("多重多态演示:");
Master master=new Master();
master.feed(new Dog(),new Bone());
master.feed(new Cat(),new Fish());
}
}
//主人类
class Master{
//给动物喂食物,使用多态,只要写一个方法
public void feed(Animal an,Food f){
an.eat();
f.showName();
}
}
//食物父类
class Food{
String name;
public void showName(){
System.out.println("食物");
}
}
//食物鱼子类
class Fish extends Food{
public void showName(){
System.out.println("鱼");
}
}
//食物骨头子类
class Bone extends Food{
public void showName(){
System.out.println("骨头");
}
}
//动物类Animal父类
class Animal{
String name;
int age;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
//动物会叫
public void speak(){
System.out.println("不知道怎么叫");
}
//动物吃东西
public void eat(){
System.out.println("不知道吃什么");
}
}
//创建Dog子类并extends继承Animal父类及覆盖speak方法
class Dog extends Animal{
//狗叫
public void speak(){
System.out.println("汪汪叫");
}
//狗吃东西
public void eat(){
System.out.println("狗爱吃骨头");
}
}
class Cat extends Animal{
//猫自己叫
public void speak(){
System.out.println("猫猫叫");
}
//猫吃东西
public void eat(){
System.out.println("猫爱吃鱼");
}
}