继承(java)
小白一枚,若有侵权,请指出,谢谢
面对对象程序设计三大特性之一:继承
继承
在原有的类的基础之上,加以拓展,从而产生新的子类(is A关系),子类其实就是父类的一种特殊情况(开发时,抽取子类共性,形成父类)
继承的格式:class 子类名 extends 父类名(继承会破坏封装)
注意:object类是所有类的根类,一个类的直接父类或者间接父类都是object类。object 表示对象,object 类是对象的封装体
子类可以继承到父类的哪些成员?
1.如果使用的public或者protected修饰,子类可以继承.
2.如果使用是包访问权限(即属性或者方法修饰符不写的情况)如果子类和父类 在同包中,可以继承,否则不可以继承.
3.父类的成员使用private,子类不能继承.
4.父类的构造器,子类不能继承.
构造器(构造方法):
子类不能继承父类的构造器(构造方法或者构造函数),但是父类的构造器重写了带有参数的,则必须在子类的构造器中显式地通过super关键字调用父类的构造器并配以适当的参数列表。
如果父类有无参构造器,则在子类的构造器中不用super调用父类构造器,系统会优先自动调用父类的无参构造器。
注意:在java中,只允许单继承,但允许多重继承,但是一般不要超过五重继承。
继承则会涉及到方法的覆盖(Override)
方法覆盖
使用原则:子类继承父类的时候,某个方法不适合子类本身,所以需要对父类的方法进行覆盖。
1.该方法若有返回值,子类的返回类型小于等于父类方法的返回类型 (例如:父类给long类型的返回值,则子类必须给小于等于long的类型)
2.子类方法不能抛出新的异常
3.子类方法的修饰符权限必须大于等于父类方法的修饰符
4.子类的方法要是想覆盖父类的方法,则方法的名称要相同,参数类型及个数要相同
最好的解决:
直接赋值父类的方法定义到子类,重新定义方法体
判断覆盖的准则
用@Override 判断是否覆盖
注意:方法的覆盖,重写,只能对方法有效。类,字段,构造器没有覆盖的概念
class Bird{ protected void fly() { System.out.println("飞得更高"); } } class Qier extends Bird { //覆盖了父类的fly()方法 @Override protected void fly() { super.fly(); System.out.println("折翼天使 飞不动 !!!!!!"); } }
public class OverrideDemo {
public static void main(String[] args) {
Bird b = new Bird();
b.fly();
System.out.println("------------------");
Qier q = new Qier();
q.fly();
}
}
super关键字
使用super关键字:指向当前对象的父类对象
super的应用场景:
1.在子类的方法中,调用父类被覆盖的方法 super.父类方法名()
2.在子类方法中,返回父类被隐藏的成员变量
3.在子类构造器中,调用父类的构造器
//动物类
class Animal1{
private String name;
private int age;
public Animal1(String name,int age) {
this.name = name;
this.age = age;
}
public void say() {
System.out.printf(this.name + " 年龄:" + this.age);
}
}
//鱼类
class Fish extends Animal1{
private String color;
//构造器
public Fish(String name,int age,String color) {
super(name,age);//用super获取父类的字段
this.color = color;
}
public void say() {
super.say();//使用super获取父类被覆盖的方法
System.out.printf(" 颜色:" + color);
}
}
//super关键字的使用
public class SuperDemo02 {
public static void main(String[] args) {
/*
* 子类的创建过程
* 先对父类初始化,再对子类初始化
* 在调用子类构造器之前,会先调用父类构造器,若父类没有重写构造器,则调用系统默认的构造器(无参)。调用时严格区分无参构造器和有参构造器
* 注意:若重写了构造器,则不能使用系统默认构造器
*/
Fish f = new Fish("小丑鱼",1,"红色");
f.say();
}
}
this关键字
使用this关键字:指向当前对象,哪个对象调用了this所在的成员,this就是哪个对象,哪一个对象调用this所在的方法,该方法中的方法的this就是哪一个对象
this的使用场景:
1.解决成员变量和局部变量的二义性(必须使用setter方法)
2.同一个类中多个实例方法间互调,当前类方法互调用this(默认可不写,标准化要写)
3.将当前对象作为参数传递给另一个方法
4.将当前对象作为方法的返回值
注意:
1.构造器重载的互调,this必须写在第一行
2.static不能与this一起使用
注意:
1.静态方法不能覆盖,静态方法属于类方法,优先于对象的存在(若对静态方法覆盖会报错)
2.静态方法与静态变量一样,属于类本身,而不属于类的某一个对象。
3.调用一个被定义为静态(static)的方法,可以通过在它前面加上这个类的名称,也可以像调用非静态方法一样通过类对象调用。
public class ThisDemo { private String name = "成员变量"; public int age; void setName(String name) { this.name = name; } //无参构造器 public ThisDemo() { System.out.println("无参数构造器!"); } //重写构造器,一个参数 public ThisDemo(String name) { this();//调用无参构造器,必须写在第一行 若重写了构造器, 则不能使用系统默认构造器,这里会出错 this.name = name; } //两个参数的构造器 ThisDemo(String name,int age){ this.name = name; this.age = age; } void show() { System.out.println("show"); } void doWork() { String name = "局部变量";//局部变量和成员变量同名,局部变量隐藏成员变量,此时可使用this解决 System.out.println(name);
System.out.println(this.name);
//将当前对象作为方法的返回值 ThisDemo append() { return this; } public static void main(String[] args) { //创建对象方法1 匿名对象,调用无参构造器 new ThisDemo();//若没有写构造器,系统默认会提供构造器。但是写了有参构造器(则系统不会再提供无参构造器),这里调用无参构造,会出错 //output:无参构造器! System.out.println("----------------"); //创建对象方法2 ThisDemo d = new ThisDemo("乔峰");//调用一个参数的构造器 output:无参构造器! 乔峰 System.out.println(d.name); System.out.println("----------------"); d.setName("lucy"); System.out.println(d.name);//output:lucky System.out.println("----------------"); new ThisDemo("zzz",45); System.out.println(d.name + "," + d.age);//output:lucky,0 为什么不是zzz,45?这里虽然调用了两个参数的构造器, //但是仍然用的是上面的引用对象,其值仍然为lucky,age为默认0 System.out.println("----------------"); //创建对象方法2 这里调用无参构造器 ThisDemo d2 = new ThisDemo();//output:无参构造器! System.out.println("----------------"); d2.show();//output:show System.out.println("----------------"); d2.doWork();//output:局部变量 ThisDemo d3 = d2.append();//这里通过append方法将当前对象作为方法的返回值,可以做其他操作 } }
1.局部变量和成员变量同名,局部变量隐藏成员变量,使用this关键字解决
2.在满足继承条件下,子类存在和父类相同的成员变量,子类变量隐藏了父类变量,使用super解决
3.在满足继承条件下,子类存在和父类相同的静态方法