目录
2.继承
2.1.继承概念
2.1.1.面向对象三大特征
2.1.2.继承与多态关系
2.1.3.继承主要解决的问题
2.1.4.继承关系当中的特点
2.1.5.封装主要解决的问题
- 我们观察如下代码:
- 以下的操作代码并没有出现了语法错误,但是出现了逻辑错误 (年龄-30岁)
- 在开发中, 为了避免出现逻辑错误, 我们建议对所有属性进行封装,并为其提供setter及getter方法进行设置和取得操作。
class Person{
String name ; // 表示姓名
int age ; // 表示年龄
void tell(){
System.out.println("姓名:" + name + ";年龄:" + age) ;
}
};
public class Demo{
public static void main(String args[]){
Person per = new Person() ;
per.name = "张三" ;
per.age = -30 ;
per.tell() ;
}
};
- 修改代码如下:
class Person{
private String name ; // 表示姓名
private int age ; // 表示年龄
void tell(){
System.out.println("姓名:" + getName() + ";年龄:" + getAge()) ;
}
public void setName(String str){
name = str ;
}
public void setAge(int a){
if(a>0&&a<150)
age = a ;
}
public String getName(){
return name ;
}
public int getAge(){
return age ;
}
};
public class OODemo10{
public static void main(String args[]){
Person per = new Person() ;
2.2、this
2.3、static
概述
重点:
per.setName("张三") ;
per.setAge(-30) ;
per.tell() ;
}
};
2.2.继承格式
* 在继承的关系中,"子类就是一个父类",也就是说,子类可以被当做父类看待。 * 例如父类是员工,子类是讲师,那么“讲师就是一个员工”,即is-a关系 * * 定义父类的格式:(一个普通的类定义) * public class 父类名称{ * //... * } * 定义子类的格式: * public class 子类名称 extends 父类名称{ * //... * } package demo1_extend; //定义一个父类:员工 public class Employee { public void method(){ System.out.println("方法被执行.."); } } package demo1_extend; //定义一个员工的子类:讲师 public class Teacher extends Employee{//子类继承父类内容} package demo1_extend; //定义员工的另一个子类:助教 public class Assistant extends Employee{ } package demo1_extend; public class Demo1 { public static void main(String[] args) { //创建一个子类对象 Teacher teacher = new Teacher(); //Teacher类当中虽然什么都没写,但会继承来自父类的method方法 teacher.method(); //创建另一个子类对象 Assistant assistant = new Assistant(); assistant.method(); //实现代码复用-method方法的复用 } }
2.3.继承中重复变量、方法的访问特点
- 继承关系中,变量看等号左侧,方法看等号右侧
package demo;
public class Demo01 {
int num=1;
public void method(){
System.out.println(num);
}
}
package demo;
public class Demo02 extends Demo01{
int num=2;
public void method(){
int num=3;
System.out.println(num);
System.out.println(this.num);
}
}
package demo;
public class DemoTest {
public static void main(String[] args) {
Demo02 demo01 = new Demo02();
System.out.println(demo01.num); //2
Demo01 demo02 = new Demo02();
System.out.println(demo02.num); //1
demo01.method();//3 2
demo02.method();//3 2
}
}
2.4.继承中成员变量访问特点
- 在父子类的继承关系中,如果成员变量重名,则创建子类对象时,访问有两种方式:
- 直接:通过子类对象访问成员变量.。等号左边是谁,就优先谁,没有则向上找。
- 间接:通过成员方法访问成员变量。方法属于谁(在哪定义),就优先用谁,没有则向上找
public class Fu { //定义成员变量(不用setter,getter,直接赋值) int numFu=10; int num=300; //定义成员方法 public void methodFu(){ //输出的是本类Fu的num,不会向下找子类 System.out.println(num); } } package demo2_extend; public class Zi extends Fu{ //定义成员变量 int numZi=20; int num=200; //定义成员方法 public void methodZi(){ //输出的是本类Zi的num,若本类无num,则向上找 System.out.println(num); } public void methodFu(){ //输出的是本类Fu的num,不会向下找子类 System.out.println(num); } } package demo2_extend; public class Demo01ExtendField { public static void main(String[] args) { Fu fu = new Fu(); //创建父类对象 System.out.println(fu.numFu); //只能使用父类东西,没有任何子类内容 Zi zi = new Zi(); System.out.println(zi.numFu); //10 子类访问父类变量 System.out.println(zi.numZi); //20 子类访问自身变量 //等号左边是谁,就优先用谁 System.out.println(zi.num); //200 zi是由Zi zi = new Zi()创建而非Fu zi= //这个方法是子类的,优先用子类的,没有再向上找 zi.methodZi(); //200 //这个方法是在父类中定义的,优先使用父类变量 zi.methodFu(); //300 Fu zii=new Zi(); System.out.println(zii.num); //300 等号左边是Fu类,优先使用 zii.methodFu();// } }
2.5.子类方法中三种变量重名
- 局部变量:直接成员变量名 访问
- 本类成员变量:this.成员变量
- 父类成员变量:super.成员变量
public class Fu { int num=10; } package demo3_extend; public class Zi extends Fu { int num=20; public void method(){ int num=30; //定义局部变量 System.out.println(num);//30 局部变量 System.out.println(this.num);//20 本类的成员变量 System.out.println(super.num);//10 父类的成员变量 } } package demo3_extend; public class Demo01ExtendField { public static void main(String[] args) { Zi zi = new Zi(); zi.method(); } }
2.6.继承中成员方法访问特点
- 在父子类的继承关系中,创建子类对象,访问成员方法的规则:
- 创建的对象是谁,就优先用谁,如果没有则向上找,即看等号右侧。
- 即继承关系中,变量看等号左侧,方法看等号右侧
- 注意事项:
- 无论是成员方法还是成员变量,如果没有都是向上找父类,绝对不会向下找子类
package demo4_extend;
public class Fu {
public void method(){
System.out.println("父类重名方法被执行");
}
}
package demo4_extend;
public class Zi extends Fu{
public void method(){
System.out.println("子类重名方法被执行");
}
}
package demo4_extend;
public class Demo01ExtendMethod {
public static void main(String[] args) {
Zi zi = new Zi();
//创建的是子类对象new Zi(),所以优先用子类方法
zi.method(); // 输出:子类重名方法被执行
/*这个涉及到对象的多态性,父类对象由子类实例化,
即是对象的多态性中的一种类型之一:向上转型
父类 父类对象=子类实例 意思就是说:我们是使用子类来实例化对象,
而这个对象却是披上了“父类对象”的名称*/
Fu zii=new Zi();
zii.method(); //输出:子类重名方法被执行
}
}
2.7.继承中方法的覆盖重写
- 1.重写的概念: 重写(override)指在继承关系中,方法的名称一样,参数列表也一样。
- 2.重写与重载区别:
- 重写(Override):方法的名称一样,参数列表【也一样】
- 重载(Overload):方法的名称一样,参数列表【不一样】
- 3.方法重写特点:创建的子类对象,则优先用子类方法
- 4.重写的方法需要满足的条件:
- 1.必须保证父子类之间方法的名称相同,参数列表也相同。@Override: 写在方法前面,用来检测是不是有效的复写, 这个注解就算不写,只要满足要求,也是正确的方法复写
- 2.子类方法的返回值类型必须【小于等于】父类方法的返回值范围。
- 提示:Object类是所有类的公共最高父类,String类就是Object类子类
- 3.子类方法的权限修饰符必须【大于等于】父类方法的权限修饰符
- 提示:public>protected>(default)>private
- 备注:(default)不是关键字default,而是什么也不是,留空
2.8.继承中覆盖重写应用
- 不要修改老版本,在新版本中添加新功能,对于已经有的旧功能可进行覆盖重写
package demo6_extend; //本来的老款手机 public class Phone { public void call(){ System.out.println("打电话"); } public void send(){ System.out.println("发短信"); } public void show(){ System.out.println("显示号码");} } package demo6_extend; //定义一个新手机,使用老手机作为父类 public class NewPhone extends Phone{ @Override public void show(){ //重写show方法,对老手机进行升级 //父类中的show功能仍需要使用 super.show(); //自己子类中又添加其他功能 System.out.println("显示姓名"); System.out.println("显示头像"); } } package demo6_extend; //继承中覆盖重写的应用:给手机添加新功能 public class Test { public static void main(String[] args) { //使用老手机功能 Phone phone = new Phone(); phone.call(); //打电话 phone.send(); //发短信 phone.show(); //显示号码 //使用新手机功能 NewPhone newPhone = new NewPhone(); newPhone.call(); //打电话 newPhone.send(); //发短信 newPhone.show(); //显示号码 显示姓名 显示头像 } }
2.9.继承中构造方法访问特点
- 1.子类构造方法中有一个默认的隐含的"super()"调用,所以一定是先调用的父类的构造方法,后执行子类构造,注意隐含的super()调用的是无参构造函数。
- 2.子类构造方法中可以通过super关键字调用父类的重载构造方法。super(参数)
- 3.super的父类构造调用,必须是子类构造方法的第一个语句,另外不能一个子类构造调用多次super构造
- 总结:
- 继承中子类必须调用父类构造方法,不写则赠送super(),写了则按定义的super调用,
- super只能有一个,还必须是第一个语句
package demo7_extend; public class Fu { public Fu(){System.out.println("父类无参构造方法"); } public Fu(int num){ System.out.println("父类重载构造方法"); } } package demo7_extend; public class Zi extends Fu{ public Zi(){ //子类构造方法中隐含着super()调用,调用父类的无参构造方法,若含参则自己写 //super(); super(20); //规则2 System.out.println("子类无参构造方法"); } public void method(){ // super(); 错误写法,规则3,super构造必须子类构造的第一个语句 } } package demo7_extend; //继承中,构造方法的访问特点 public class Demo01Constructor { }
1.10.super关键字三种用法
- super关键字三种用法 super关键字访问父类内容
- 1.在子类的成员方法中,访问父类的成员变量
- 2.在子类的成员方法中,访问父类的成员方法
- 3.在子类的构造方法中,访问父类的构造方法
package demo8_extend; public class Fu { int num=10; public void method(){System.out.println("父类成员方法"); } } package demo8_extend; //super关键字三种用法 super关键字访问父类内容 public class Zi extends Fu{ int num=20; public Zi(){ super(); } //子类构造访问父类构造,可省略,系统默认 public void methodZi(){ //子类成员方法访问父类成员变量 System.out.println(super.num); //10 } public void method(){ //子类成员方法访问父类成员方法 super.method(); //输出:父类成员方法 } }
1.11.this关键字三种用法
- this关键字三种用法 this关键字访问本类内容
- 1.在本类的成员方法中,访问本类的成员变量
- 2.在本类的成员方法中,访问本类的另一个成员方法
- 3.在本类的构造方法中,访问本类的另一个构造方法。(与super不同)
- 第3种用法注意事项:
- A.this(参数)也必须是构造方法中第一个语句,且唯一
- B.super和this两种构造调用不能同时使用,有this无super
- C.无参构造中的this不能无参,否则就是调用自身(成递归),有参构造中可以。
-
package demo9_extend; public class Fu { int num=10; } package demo9_extend; //this关键字三种用法 this关键字访问本类内容 public class Zi extends Fu { int num=20; public Zi(){ //super(); 这一行不再赠送 this(10);//3.本类构造调用本类另一个构造,this必须是第一个语句 } public Zi(int m){ System.out.println("本类含参构造方法被调用"); } public void showNum(){ int num=30; System.out.println(num);//局部变量30 System.out.println(this.num);//1.本类变量20 System.out.println(super.num);//父类变量10 } public void methodA(){ System.out.println("AAA"); } public void methodB(){ //2.在本类的成员方法中,访问本类的另外一个成员方法 this.methodA(); //强调该方法是本类的 System.out.println("BBB"); } }
1.12.this与super关键字图解
- 首先通过类加载器将类以字节码加载到方法区,然后将main方法压住栈中执行,
- 先在栈中声明变量Zi zi,然后在堆中开辟空间创建zi对象,
- 然后把zi.show()方法压入栈中执行,在该方法中分别调用局部变量、this本类变量、super父类变量;
- 然后把zi.method()方法压住栈中执行,该方法先调用super.method()方法,即先把父类的method压入栈中执行完并销毁后继续执行zi.method方法,执行完销毁method内存,至此main方法执行完毕也被销毁。
package demo10_extend;
public class Fu {
int num=10;
public void method(){ System.out.println("父类方法"); }
}
package demo10_extend;
public class Zi extends Fu{
int num=20;
@Override
public void method(){
super.method(); //子类调用父类方法
System.out.println("子类方法");
}
public void show(){
int num=30;
System.out.println(num);//30
System.out.println(this.num);//20
System.out.println(super.num);//10
}
}
package demo10_extend;
//super与this关键字图解
public class Demo {
public static void main(String[] args) {
Zi zi = new Zi();
zi.show();
zi.method();
}
}
1.13.java继承的三个特性