一.什么是继承
首先,继承是java面向对象语言中的一个重要特性,,它允许一个类继承另一个类的成员变量,成员方法,并在这个基础上进行改变 , 例如动物是哺乳动物的父类,哺乳动物在大部分特性上与动物相同,但是有个别性质上发生了改变,并且可能多出某些性质,这就是继承
class Animal{
public String name;
public int age;
public String color;
public Animal(String name) {//自己写父类的带参构造函数的时候,则需要让子类中也进行构造,否则编译错误;
this.name = name;
System.out.println("Animal(String)");
}
public Animal(){
System.out.println("默认初始化父类");
}
public void eat() {
System.out.println(name+" 正在吃饭!---Animal");
}
}
这是一个父类对象(动物),它里面存在着它的相关成员变量和成员方法。
在java中想要使用继承需要关键词extends
访问限定符 class 子类名 extends 父类名
class Dog extends Animal{
public Dog(String name) {
super(name);//调用父类的构造函数,super是关键词可以调用父类构造函数,且必须在第一行super(参数)
//super不可与this();一起出现,因为都要在第一行;
System.out.println("DOG的构造方法!");
}
//就算自己不去构造构造函数,系统也会自动为父类和子类构造构造函数
public Dog(){
super();//可以不写这个,因为编译器会自动为你写一个;(在父类中同理)
System.out.println("默认初始化子类");
}
public void wangWang() {
System.out.println(name+" 正在旺旺旺!!");
}
public void eat() {
System.out.println(name+" 正在吃狗粮!");
}
}
这样,我们就完成了一个初步的继承了,Dog这个类就继承了父类animal的全部成员,包括private成员变量,并且在此之上还进行了某些修改和增加
在Java中,当涉及到面向对象编程中的继承机制时,子类确实会继承父类的所有成员,包括私有(private)成员。不过需要注意的是,虽然子类继承了这些私有成员,但是由于访问控制的原因,子类并不能直接访问或修改这些私有成员。
二,为什么要继承
在Java中,继承和现实中的继承有些类似,但又大相径庭,在Java中的继承本质上是对共性的抽取,从而实现代码的复用,达到简化代码的作用,提高代码的可读性以及代码 的编写效率。
三,如何使用继承呢
public class demo1 {
public static void main(String[] args) {
Dog dog = new Dog();
Dog dog2=new Dog("唐鱼");
dog2.eat();
dog2.wangWang();
}
}
1、子类会将父类中的成员变量或者成员方法继承到子类中
2、子类继承父类之后,必须要添加自己特有的成员,体现出与基类的不同,否则就没有必要继承了。
如果在子类与父类中出现同名的成员,编译器会优先访问子类本身的成员,和局部变量一样,优先访问内部的,如果需要在子类中访问父类的同名成员,那么需要使用super关键字。该关键字能够特指访问父类的成员,父类的成员变量,成员方法均可通过super关键字特指访问,但是切记,super只能在子类中使用。
父类
class Animal{
public String name="小花";
public int age=10;
public String color="blue";
}
子类
class Dog extends Animal{
int age=15;
public String name="小王";
public void test(){
System.out.println(this.age);
System.out.println(this.name);
System.out.println(super.age);
System.out.println(super.name);
}
在子类方法中 或者 通过子类对象访问父类成员时:
1、如果访问的成员变量中子类有,则编译器中优先访问子类的成员变量
2、如果访问的成员变量中子类没有,则编译器访问父类继承下来的,如果父类也没有,则编译报错
3、如果访问的成员变量与父类中的成员变量同名,则优先访问子类自己的
4、通过子类对象访问与父类同名方法时,如果父类和子类同名方法的参数列表不同(构成重载),根据调用的方法传递的参数选择合适的方法进行访问,如果没有则编译报错;如果参数列表相同(构成重载),那么需要使用super关键字才可以特指访问父类的方法,否则默认访问子类的方法
四,super关键字的介绍
当场景需要或者程序员设计问题,子类和父类中有可能会出现名称相同的成员,如果想要在子类中访问父类的同名成员,那么就需要使用到super关键字,该关键字的主要作用是:在子类中特指访问父类成员.
关键字访问父类的成员时需要使用super关键字,super关键字是获取子类对象中从父类继承下来的部分
如果子类和父类的方法构成重载,可以直接通过参数列表区分访问父类还是子类的方法
如果子类和父类 的方法构成重写,此时需要调用父类的方法则需要使用super
class Base{
public int a;
public int b;
public int c;
public void func1(){
System.out.println("父类func1()");
}
}
public void func1(int a) {
System.out.println("func1(int)");
}
public void func1() {
System.out.println("子类func1()");
}
public void testFunc() {
func2();
func1(10);//子类的 重载!!
func1();//子类的
super.func1();//可以在子类中通过super来调用父类中的成员
}
注意:super调用父类只能在非静态成员方法中调用,因为super依赖于对象,在子类方法中通过super才能调用父类成员。
那么有人就要问了,主播主播,在子类中有没有明确方法可以调用自身的成员呢?
这当然是有的,有的!这个就是this,这个在之前类和对象也有过学习
通过this.()调用自身方法,通过类似this.a调用自身成员变量,这个和默认是一样的
public void testFunc() {
func2();
func1(10);//子类的 重载!!
this.func1();//子类的
super.func1();//可以在子类中通过super来调用父类中的成员
}
五,子类和父类的构造函数
相信大家总是被子类和父类的构造函数的编译错误所困扰过,这次我一次讲清
首先,我们可以将构造方法大体分为2中:显示构造和默认构造
其次,我们可以继续细分显示构造为无参和含参
当父类中显示定义的是无参构造方法或者父类没有定义构造方法时,子类中显示定义了含参构造方法,或者是没有显示定义构造方法,或者是显示定义无参的构造方法,编译器会自动调用父类的构造方法,不需要我们手动调用。
public Animal(){
System.out.println("默认初始化父类");
}
public Dog(){
super();//可以不写这个,因为编译器会自动为你写一个;(在父类中同理)
System.out.println("默认初始化子类");
}
这也就意味着:子类中的构造方法都会默认调用父类的构造方法,并且是先执行父类的构造方法才执行子类的构造方法 。先有父后有子
当父类显示定义含参的构造方法时,编译器就不会在子类的构造方法中自动调用父类的构造方法,此时就需要我们手动调用了。否则就会出现编译报错
public Animal(String name) {//自己写父类的带参构造函数的时候,则需要让子类中也进行构造,否则编译错误;
this.name = name;
System.out.println("Animal(String)");
}
public Dog(String name) {
super(name);//调用父类的构造函数,super是关键词可以调用父类构造函数,且必须在第一行super(参数)
//super不可与this();一起出现,因为都要在第一行;
System.out.println("DOG的构造方法!");
}
由四,五总的来说:
super关键字有三个用处:
1、通过super关键字调用父类的成员变量
2、通过super关键字调用父类的成员方法
3、通过super( )调用父类的构造方法使用super()时候需要注意的几点:
1、super()的参数列表需要和父类构造方法的参数列表一致
2、super()必须要在构造方法中的第一条语句
3、子类的构造方法的参数列表需要含有父类构造方法的参数
4、super()只能在子类构造方法中出现一次,并且不能和this()同时出现
5、若父类显示定义无参或者默认的构造方法时,在子类构造方法第一行默认有隐含的super()调用,即调用父类的构造方法
6、如果父类构造方法是带有参数的,此时需要程序员为子类显示定义构造方法,并在子类构造方法中选择适合的父类构造方法调用,否则编译失败。7.由此可以得出为什么super关键字依赖于子类,因为在子类对象被构造的时候才调用父类的构造函数,所以说super依赖于子类对象
六,继承中的初始化
常用的代码块的作用基本上是对对应的变量进行初始化,而不同给代码块之间的执行顺序是不一样的。在没有继承的基础上代码块之间的执行顺序是:静态代码块,构造代码块,构造方法,那么我们就有疑问,我们在继承中的顺序是什么呢?
通过一系列代码的实现我们可以得出,它的顺序是
1.父类的静态代码块
2.子类的静态代码块
3.父类的构造代码块
4.父类的构造方法
5.子类的构造代码块
6。子类的构造方法
父子类的出现也使得访问权限被细分为更多种
七,多继承
java中支持多继承和单继承,但是不支持菱形继承(c++中支持)
如果不想被继承,可以使用final修饰类,表示当前类不支持被继承
final的作用:
1、修饰变量,表示常量,不可更改
2、修饰类,表示当前类不可被继承
3、修饰方法,表示当前方法不支持被重写
八,组合
组合不是一种思想,而是一种编写代码的手段,组合是一种表达类之间关系的方式,也能够达到重用代码的效果
仅仅是将一个类的实例作为另外一个类的成员变量
class Student {
int a=3;
}
class Teacher {
}
//组合 其实就是代码的 实现方式
class School {
public Student student;
public Teacher teacher;
}
public class Test3 {
public static void main(String[] args) {
School sc=new School();
sc.student=new Student();
System.out.println(sc.student.a);
}
}