Java中的三大基本特征--继承
前言
今天我们将学习Java中的三大基本特征之一的继承。说到继承,我们一想到的就是王思聪,儿子继承父亲的财产,那么在Java中,子类是否也全部继承了父类的成员呢?
一、什么是继承
格式:
A extends B
表现为A继承于B
继承是指子类可以继承父类所有非私有的成员,但不能继承父类的构造器和私有成员。其实目前对于子类是否可以继承父类的私有成员尚有争议,个人认为子类会继承私有变量,只不过是因为private修饰符的限制导致子类不能直接的访问,需要通过继承的方法来访问私有成员,如get()方法等等。(个人理解,仁者见仁智者见智啊哈哈~~)
public class Demo {
public static void main(String[] args) {
//创建第一个儿子对象
Son son1 = new Son("奔驰","小明",18);
//创建第二个儿子对象
Son son2 = new Son("宝马","小王",19);
System.out.println(son1.toString());
System.out.println(son2.toString());
}
}
class Father{
private String carName;
public Father(String carName) {
this.carName = carName;
}
public Father() {
}
public String getCarName() {
return carName;
}
public void setCarName(String carName) {
this.carName = carName;
}
}
class Son extends Father{
String name;
int age;
public Son(String carName, String name, int age) {
super(carName);
this.name = name;
this.age = age;
}
public Son(String name, int age) {
this.name = name;
this.age = age;
}
@Override
public String toString() {
return "Son{" +
"name='" + name + '\'' +
", age=" + age +'\'' +
", carName="+this.getCarName()+
'}';
}
}
这里Father类中的carName定义为私有变量,但Son子类仍然可以通过getCarName()方法对父类中的私有方法进行操作,并且main方法中定义了两个Son对象,对父类的carName变量赋值,重写toString()方法后输出两个对象的属性值也是不同的,这里我个人认为子类也可以继承父类的私有成员,只不过不能直接使用。
二、继承的设计规范和图解
继承的设计规范是把几个类中共有的变量和方法提取出来放在父类中,把特殊的方法放在子类中,然后让子类来继承父类即可,这样子类都能使用父类中的非私有成员,提高了代码的复用性
三、继承的特性
3.1 单继承
Java中的继承是单继承,即一个类只能继承一个父类,不过却支持多层继承,就是儿子继承自父亲,父亲又继承自爷爷,所以儿子也能使用爷爷中的成员,但一个父类可以有多个子类。单继承的缺点就是不够灵活,不方便切换各种的业务,以后我们会学到接口,一个子类是支持实现多个接口的,更加的灵活
3.2 方法的重写
方法的重写即重新编码从父类中继承的方法,当我们从父类中继承的方法不足以实现我们的业务时就要重写方法,重写的要求是方法名和参数列表要一模一样,子类方法的访问权限要大于等于父类的,返回值范围要小于等于父类的,但是父类中的私有方法和静态方法不能重写
class Animal{
String name;
int age;
public Animal(String name, int age) {
this.name = name;
this.age = age;
}
public Animal() {
}
public void eat(){
System.out.println("动物在喝水~~");
}
//省略set()和get()方法
}
class Cat extends Animal{
//重写了父类Animal类中的eat()方法
@Override
public void eat() {
System.out.println("小猫在喝水~~");
}
}
3.3 补充
父类的静态成员在继承中是怎么继承的?
个人理解:我认为静态成员是继承不了的,因为用static修饰的成员本来就是共享的,可以通过类名调用的,虽然子类继承后,可以通过子类名.静态成员调用,但实际上它是调用父类的静态成员,而不是子类的,通过这种方式调用的时候,会先到子类中寻找,找不到的话就去父类中找
public class Demo1 {
public static void main(String[] args) {
Cat cat = new Cat();
Cat.test();
Cat.a = 2;
System.out.println(Cat.a);//2
System.out.println(Dog.a);//2
System.out.println(Animal.a);//2
//a改变后的值仍然和Cat、Dog两个子类共享
}
}
class Animal{
public static int a = 1;
public static void test(){
System.out.println("我是父类的静态方法");
}
}
class Cat extends Animal{
}
class Dog extends Animal{
}
四、子类访问成员的特点
Java中允许子类和父类中的变量重名,只不过重名后子类将不再继承父类的这个变量。在子类中,我们可以使用this访问本类中的成员,即this.变量名/方法名,使用super访问父类中的成员,即super.变量名/方法名
class Animal{
String name = "动物";
int age = 999;
public void eat(){
System.out.println("动物在喝水~~");
}
//省略set()和get()方法
}
class Cat extends Animal{
String name = "加菲猫";
int age = 18;
//重写了父类Animal类中的eat()方法
@Override
public void eat() {
System.out.println("小猫在喝水~~");
}
public void pintInfo(){
System.out.println(this.name);//加菲猫
System.out.println(this.age);//18
System.out.println(super.name);//动物
System.out.println(super.age);//999
}
}
五、子类访问构造器的特点
子类访问父类构造器使用super,即super(…)
子类访问兄弟构造器使用this,即this(…)
注意:这种形式都只能在构造器中调用,兄弟构造器的意思是本类中的其它构造器
class Animal{
String name;
int age;
//省略set()和get()方法
}
class Cat extends Animal{
Cat() {
this("霍雨浩");
}
Cat(String name){
//super(..); 默认调用父类构造器,如果第一行调用了兄弟构造器就不会调用super(..)
this.name = name;
System.out.println("我是兄弟构造器");
}
}
六、this和super的总结
super()和this()只能在子类的构造器中使用,而且必须在第一行中优先调用,并且这两者不能共存,在一个构造方法中只能有一个,原因是每一个子类构造器的第一行会默认调用一个super(),如果在子类构造器中调用了兄弟构造器,又调用父类构造器,本身兄弟构造器第一行就会调用父类构造器,这一顿操作下来就调用了两次,所以Java默认不能把兄弟构造器和父类构造器写一起(个人理解)
格式 | 作用 |
---|---|
this.xxx | 调用子类当前对象的成员 |
super.xxx | 调用父类中的成员 |
this(…) | 调用本类兄弟构造器 |
super(…) | 调用父类构造器 |
七、权限修饰符
修饰符 | 作用范围 |
---|---|
pulic | 本类、同一个包下的其它类、任意包下的子类里、任意包下的任意类中 |
protect | 本类、同一个包下的其它类、任意包下的子类 |
default(默认什么都不写) | 本类、用一个包下的其它类 |
private | 本类 |
八、总结
通过本文,我们学习到了Java中的继承,和我们日常生活中的继承很相似,Java中的继承很像我们所说的父母传递给孩子的特征,父母的一些特征被我们继承,而Java中也是,子类会继承父类的非私有成员,而不会继承私有成员和构造方法,这让我想起了电影《满城尽带黄金甲》中的一句话:“天地万物,朕赐给你,才是你的;朕不给,你不能抢”,有没有觉得继承就是这种感觉。