Java继承
同现实生活一样,子女会多多少少保留父母的一些特征,这被称为继承,Java中一个类具有另一个类的所有属性方法并且具有新的属性方法,那么这个类继承了另一个类,称为子类,另一个类称为父类。
继承是面向对象最显著的一个特性。继承是从已有的类中派生出新的类,新的类能吸收已有类的数据属性和行为,并能扩展新的能力。
类的层次分层次:
- 类的共同属性和行为(如动物):属性(大小,重量);行为(吃,喝,睡)
- 设计具有共同属性和行为的类为父类
- 决定子类是否有特殊的行为或属性可以形成较次一级的类
这样一级一级的有了层次的分层继承的目的在于提高代码的复用性,既然有相同的属性,直接继承就可以避免再次书写代码
public class Inheritance {
public static void main(String[] args) {
Sheep sheep = new Sheep();
Tiger tiger = new Tiger();
sheep.eat();// 羊继承了食草动物,吃草来自于食草动物的特殊行为
sheep.drink();// 羊继承了食草动物,食草动物继承了动物,喝水来自于动物共有的行为
tiger.eat();// 老虎继承了食肉动物,吃肉来自于食肉动物的特殊行为
tiger.drink();// 老虎继承了食肉动物,食草肉动物继承了动物,喝水来自于动物共有的行为
// 因为继承了动物这个父类,所以子类的对象同样具有这些属性
System.out.println(sheep.getWeight());
System.out.println(sheep.getWidth());
}
}
// 羊是动物的一个子类,它有动物的所有特征也有自己的属性
class Sheep extends EatGrass{
private String color;
}
class Tiger extends EatMeat{
private String color;
}
// 还可以根据食肉和食草来分类,同样为动物的子类
class EatMeat extends Animal{
public void eat(){
System.out.println("吃肉");
}
}
class EatGrass extends Animal{
public void eat(){
System.out.println("吃草");
}
}
// Animal 是父类它具有动物的所有相同的属性和方法
class Animal{
private int width;
private int weight;
private boolean hunger;
public void drink(){
System.out.println("喝水");
}
public void sleep(){
System.out.println("困了休息睡觉");
}
public int getWidth() {return width; }
public void setWidth(int width) { this.width = width; }
public int getWeight() { return weight; }
public void setWeight(int weight) { this.weight = weight; }
public boolean isHunger() { return hunger; }
public void setHunger(boolean hunger) { this.hunger = hunger; }
public boolean isTried() { return tried; }
public void setTried(boolean tried) { this.tried = tried; }
}
继承时成员变量的使用
在继承中如果子类有和父类相同的属性,那么优先选用之类的属性而不是继承来的属性
public class Inheritance {
public static void main(String[] args) {
Sheep sheep = new Sheep();
// 类中hunger为false,子类中为true,继承中如果子类有和父类相同的属性
System.out.println(sheep.hunger);
System.out.println(sheep.getHungerThis());
System.out.println(sheep.getHungerSuper());
}
}
class Sheep extends EatGrass{
public boolean hunger = true;
public boolean getHungerThis(){
return this.hunger; // this 关键字指向当前对象及调用它的 sheep
}
public boolean getHungerSuper(){
return super.hunger; // super 关键字引用父类,所以此处的 hunger为继承来的的值
}
}
class Animal{
public boolean hunger = false;
}
输出结果如图:
总结起来就是:
- 子类可以继承父类中的属性
和访问修饰符有关,public同类、同包、子类、不同包均可继承;protected除了不同包均可继承;默认修饰符同类同包均可继承;private则不可继承 - 子类和父类有同名属性的时候 访问和方式有关:
子类对象.属性 – 得到子类的属性
关键字this获取 – 得到子类的属性
关键字super获取 – 得到父类继承来的属性
继承时构造方法的使用
public class Inheritance {
public static void main(String[] args) {
Sheep sheep = new Sheep();
}
}
class Sheep extends EatGrass{
private String color;
public Sheep(){
System.out.println("子类构造方法");
}
}
class EatGrass extends Animal{
public void eat(){
System.out.println("吃草");
}
}
// Animal 是父类它具有动物的所有相同的属性和方法
class Animal{
public Animal(){
System.out.println("父类构造方法");
}
}
输出如下:
父类构造方法
子类构造方法
从输出结果中可以看出子类对象在建立时首先建立父类对象(今后对于对象建立都称为对象实例化),即先调用父类构造函数,再调用子类构造函数
public class Inheritance {
public static void main(String[] args) {
Sheep sheep = new Sheep();
}
}
class Sheep extends EatGrass{
private String color;
public Sheep(){
System.out.println("子类构造方法");
}
}
// Animal 是父类它具有动物的所有相同的属性和方法
class Animal{
public Animal(boolean hunger){
System.out.println("父类有参构造方法");
this.hunger = hunger;
}
}
和其他的对象实例化一样,如果有了自己的构造方法,默认的无参构造方法将不会自动添加,运行将会产生报错,因为主函数使用的是子类的无参构造方法,则必须调用父类的无参构造方法实例化父类对象
class Sheep extends EatGrass{
private String color;
public Sheep(){
super(true);
System.out.println("子类构造方法");
}
}
但是修改成这样之后仍然便可以使用,super和this关键字一样可以调用构造方法,区别为一个是this是当前对象的,super是父类的。
简单理解就是没有传参是之类的构造方法默认在第一行有super( )调用父类的无参构造方法先初始化父类对象,接着往下执行,完成子类对象实例化
继承时成员方法的使用(重写)
public class Inheritance {
public static void main(String[] args) {
Sheep sheep = new Sheep();
sheep.eat();
}
}
// 羊是动物的一个子类,它有动物的所有特征也有自己的属性
class Sheep extends EatGrass{
public void eat(){
System.out.println("吃青草");
}
public Sheep(){
super(true);
}
}
class EatGrass extends Animal{
public EatGrass(boolean hunger) {
super(hunger);
}
public void eat(){
System.out.println("吃草");
}
}
// Animal 是父类它具有动物的所有相同的属性和方法
class Animal{
public int width ;
public int weight ;
public boolean hunger = false;
public Animal(boolean hunger){
this.hunger = hunger;
}
}
方法的继承和属性差不多,同样的如果子类有同名的方法会优先使用,没有则使用父类继承来的的方法
像这样几个方法,方法名相同,传递参数(类型和数量)和返回值也相同就称为方法重写主要就是在子类重写和父类方法 方法名 传参 以及返回值(jdk1.5只有只要类型和父类相同即可)相同的方法
什么叫返回类型相同
通过代码来看:
class Sheep extends Animal{
public Sheep() {
super(true);
}
// 返回类型是Sheep类型的,它继承了Animal类在父类中可以看出父类的eat方法正式Animal类型
public Sheep eat(){
System.out.println("吃青草");
return null;
}
}
// Animal 是父类它具有动物的所有相同的属性和方法
class Animal{
public int width ;
public int weight ;
public boolean hunger = false;
public Animal(boolean hunger){
this.hunger = hunger;
}
// 返回 Animal 类型的值
public Animal eat(){
System.out.println("吃草");
return null;
}
}
注:
- 在继承的时候子类不能够缩小父类的访问权限即子类方法的访问权限不能比父类的访问权限小(四种访问权限如图,详解在封装处
- 静态的方法只能重写为静态的