目录
1.继承的定义与使用
1.1继承的实现
1.2 继承的限制
2.覆写
2.1 方法的覆写
2.2 属性的覆写(了解)
2.3 super关键字
3.final关键字——终结器
3.1 final修饰类(String类以及8大基本数据类型的包装类,Integer)
3.2 final修饰方法
3.3 final修饰属性——常量
4.多态
class 子类 extends 父类
子类对象实例化前一定会首先调用父类的构造方法,实例化父类对象后再调用子类构造方法,进行子类对象初始化。
public class Super{
public static void main(String[] args){
new Son("abc");
}
}
class Father{
//无参数的构造方法——默认的构造方法 public Father(){}
}
class Son extends Father{
public Son(String name){
//Father super();
}
}
代码示例:
public class Inherit{
public static void main(String[] args){
//学生继承了Person类,而Person类由于有自定义的构造方法,因此没有默认的构造方法
//所以必须在Student中定义构造方法
Student student = new Student("Jack","男","1","bit");
//调用Student.toString,而Student.toString是继承Person.toString
//因此打印的是Person.toString
System.out.println(student);
}
}
//学生在Person的基础上增加学号、学校
//Person是Student的父类
//Studnt是Person的子类
class Student extends Person{
private String num;
private String school;
public Student(String name,String gender,String num,String school){
//虽然Student继承了Person,但是由于name、gender是私有的,因此Student不能访问
//this.name=name; //error
//直接赋值 ->能够访问到父类的属性(属性不是私有的,父类提供无参的构造方法)
//通过构造方法 -> 父类提供构造方法(带参数)
//通过setter方法 ->能够访问到父类的setter方法
super(name,gender); //调用父类的构造方法
this.num=num;
this.school=school;
System.out.println("这是子类的构造方法");
}
public String getNum(){
return this.num;
}
public String getSchool(){
return this.school;
}
//方法覆写
public String toString(){
return super.toString()+" 学号:"+this.num+" 学校:"+this.school;
}
// public String toString(){
// return " 姓名:"+this.getName()+" 性别:"+this.getGender()+" 学号:"+this.num+" 学校:"+this.school;
// }
}
//面向对象的一个特性——封装,对方封装好的部分进行扩展,
//开闭原则:对扩展开放,对修改关闭
class Person{
private String name;
private String gender;
//构造方法
public Person(String name,String gender){
this.name=name;
this.gender=gender;
System.out.println("这是父类的构造方法");
}
//getter方法
public String getName(){
return this.name;
}
public String getGender(){
return this.gender;
}
public String toString(){
return " 姓名:"+this.name+" 性别:"+this.gender;
}
}
如果子类定义了与父类完全相同(不算权限)的方法或者属性的时候,这样的操作称为覆写。
子类定义了与父类方法名称、参数列表、返回值完全相同的方法。被覆写的方法不能拥有比父类更为严格的访问控制权限。
判断调用的是父类方法或子类方法:
a.看new在哪儿(当前使用的对象是通过哪个类new的)
b.调用的方法是否被子类覆写,如果被覆写,调用的一定是被覆写后的方法。
练习:
解释方法重载与方法重写的区别
a.概念上:
方法重载:方法名相同,参数列表不同,与返回值无关。
方法重写:子类定义了和父类方法名称、参数列表、返回值完全相同的方法,只是权限不同。
b.范围上:
方法重载:在同一个类中
方法重写:在有继承关系的类之间
c.权限要求:
方法重载:没有权限要求
方法重写:被覆写的方法不能拥有比父类更为严格的访问控制权限
当子类定义了和父类属性名称完全相同的属性的时候,就称为属性的覆写。
属性覆写不对访问控制权限有要求,因为属性是通过内部来进行访问。
/**
* 方法覆写
* Author:qqy
*/
public class Test11{
public static void main(String [] args){
Person person=new Person();
person.print();
Student student=new Student();
//就近原则
System.out.println(student.getName());
}
}
class Person{
public String name="Jack";
//成员方法
public void print(){
System.out.println("这是Person的print方法");
}
private void hello(){
System.out.println("这是Person的hello方法");
}
}
class Student extends Person{
//属性覆写
private String name="Tom";
//default——包私有
//public>protected>[default]>private
public void print(){
System.out.println("这是Student的print方法");
}
//此时,子类的hello方法并不是方法覆写
//因为父类中的hello方法是私有的,子类已经看不见父类的hello方法
//因此,这只是子类的普通方法,与父类的方法没有任何关系
public void hello(){
System.out.println("这是Student的hello方法");
}
public String getName(){
return name;
}
}
2.3.1 super用于方法
1. 用于构造方法,表示调用父类构造方法 super(参数列表)
a.当子类调用父类无参构造时,super( )可写可不写,表示父类无参构造;
当子类调用父类有参构造时,super(参数列表)必须要写,告诉编译器当前调用的是哪个有参构造
b.子类构造方法中调用父类构造必须是第一行语句
c. this与super不能同时调用
2. 用于普通方法,super.方法名(参数)
用于在子类中,明确调用父类被覆写的方法
2.3.2 super用于属性(了解)
super.属性名 表示调用父类中被覆写的属性(权限不是private)
代码示例:
class Person{
public String str="daddy";
public void fun(){
System.out.println("父类");
}
}
class Student extends Person{
public String str="child";
public void fun(){
//明确调用父类被覆写的fun方法
super.fun();
System.out.println("子类");
//明确调用父类被覆写的属性
System.out.println(super.str);
}
}
public class Test1{
public static void main(String [] args){
System.out.println(new Student().str);
new Student().fun();
}
}
被final修饰的类不能被extends(编译无法通过)
final修饰内部类,只能被子类使用
final修饰的属性、变量(引用)、参数,一旦初始化后就不能再赋值了
一旦一个类被final修饰,该类的所有方法都会默认加上final(成员变量不会加final)
被final修饰的全局变量必须在声明时初始化(静态块初始化),并且在初始化后值无法修改。
练习:
a和b的区别:
class Person{
public final int a=5;
public static final int B=10;
}
a : final变量——常量(值不能改变,每个对象都有自己的final变量,在对象产生时初始化)(对象)
b : static final变量——全局常量(所有对象共享此变量,类加载时初始化,效率较高,通过类名调用),存储于全局数据区。字母全大写,下划线分隔。(类)
代码示例:
class Person{
public String name="daddy";
public int age=20;
}
public class Test1{
public static void main(String [] args){
final Person p=new Person();
//p的地址不变
//p=new Person(); //error
//内容可以改变
p.name="hello";
p.age=30;
System.out.println(p.name);
System.out.println(p.age);
}
}
练习:
public class Test1{
byte b1=2,b2=2,b3,b4;
final byte b5=4,b6=5,b7=8;
public void test(){
//假设下列语句没有关联性
//b3是byte型,b1+b2的结果是int型,需强转
b3=b1+b2; //error
//b4是byte型,b5、b6有final修饰,相加结果仍为byte型
b4=b5+b6;
//b5被final修饰,值不可修改
b5=b1+b3; //error
//b3是byte型,b4是int型,b4+b5结果为int型,需强转
b3=b5+b4; //error
}
}
父类 父类引用 = new 子类( );
向下转型(强制):当父类引用需要调用子类扩充方法时,才需要向下转型
子类 子类引用 = (子类)父类实例;
public class Test1{
public static void main(String[] args){
//向上转型
//父类 父类引用 = new 子类( );
Person per=new Student();
per.fun(); //子类
System.out.println(per.getPersonInfo()); //Person info
//Student给的是子类对象,但变量类型是Person
//使用时,将一个Student变量当Person来用
//我们所看到的属性、方法,是Person中定义的
//Person中没有定义getStudentInfo(),因此下行代码错误
//System.out.println(per.getStudentInfo()); //error
//向下转型
//子类 子类引用 = (子类)父类实例;
Student stu=(Student)per;
//1. Student stu=(Student)new Person(); //编译通过,无法运行(CCE)
//2. Person per1=new Person();
// Student stu1=(Student)per1; 1、2等价
stu.fun(); //子类
System.out.println(stu.getPersonInfo()); //Person info
System.out.println(stu.getStudentInfo()); //Student info
}
}
class Person{
public void fun(){
System.out.println("父类");
}
public String getPersonInfo(){
return "Person info";
}
}
class Student extends Person{
public void fun(){
System.out.println("子类");
}
public String getStudentInfo(){
return "Student info";
}
}
public class Test6{
public static void main(String[] args){
Person per=new Person();
//per可以由Person类创建,返回true
System.out.println(per instanceof Person);
//如果per不能由Student创建
if(!(per instanceof Student)){
per=new Student();
System.out.println(per instanceof Student);
}
}
}
class Person{
public void fun(){
System.out.println("父类");
}
}
class Student extends Person{
public void fun(){
System.out.println("子类");
}
}
class Person{
public void fun(){
System.out.println("人类");
}
}
class Student extends Person{
public void fun(){
System.out.println("学生");
}
}
class Worker extends Person{
public void fun(){
System.out.println("工人");
}
}
public class Test1{
public static void main(String[] args){
Test1(new Person()); //人类
//向上转型
Test1(new Student()); //学生
//向上转型
Test1(new Worker()); //工人
}
public static void Test1(Person per){
per.fun();
}
}