1.什么时候用继承?继承解决了什么问题?
1.1 为什么要继承
1.接下来我会用代码进行解释。在下面的代码中我定义了两个类分别是cat 和 dog类这两个类中分别由两个重复的属性是 name 和 age ,那么我们要简化这段代码要如何简化?
class Dog {
public String name;
public int age;
public void eat() {
System.out.println("正在吃");
}
}
class Cat {
public String name;
public int age;
public void barks() {
System.out.println("正在喵喵叫");
}
}
public class Frank {
public static void main(String[] args) {
Cat cat = new Cat();
Dog dog = new Dog();
}
}
2.我们可以把他们的共性提取出来,也就是相同的属性,将这个做一个合集类,而这个类就是我们的父类。我们将这个将他们共性提取出来的类起名为animal。代码如下。
class Animal{
public String name ;
public int age ;
}
class Dog extends Animal{
public void eat() {
System.out.println("正在吃");
}
}
class Cat extends Animal{
public void barks() {
System.out.println("正在喵喵叫");
}
}
public class Frank {
public static void main(String[] args) {
Cat cat = new Cat();
Dog dog = new Dog();
}
}
3.在上面图中的代码可以发现,类的开头出现了一个单词(extends(扩展)),通过这样的样式,cat和dog就具有了Animal中的特征就不需要再定义一个age和name。
4.Animal称之为父类,基类和超类(这三者意思相同),cat和dog被称为子类派生类。
5.总的来说继承就是对子类代码共性的抽取,对代码进行服用。
关系是:is a 的关系
Dog is a Animal。
Cat is a Animal。
2.继承的详细使用。
2.1.1 子类到底继承了父类的什么
1.子类继承了父类的方法和成员变量,static修饰的是不能继承的,因为static修饰的不依赖于对象。
2.1.2 注意事项
1.父类和子类要有区别,子类中定义的方法和变量要和父类不同,要不然你定义父类干什么和父类一样,那你还不如不用继承。
2.子类和父类不存在相同的成员变量。(你可以可以理解为合法却有病)
2.1 .3 疑问 ?
2.1.3.1 如果子类和父类中存在相同的成员变量,我进行输出,输出的是父类的成员变量还是子类的成员变量?
我在下图代码,Dog类中定义了一个age = 20 ,在main方法中调用了子类Dog的age,这时候输出的结果是20,也就是访问了子类中的成员变量。(可以理解为优先访问自己的,然后再访问父类)
class Animal{
public String name ;
public int age ;
}
class Dog extends Animal{
int age = 20 ;
public void eat() {
System.out.println("正在吃");
}
}
//class Cat extends Animal{
// public void barks() {
// System.out.println("正在喵喵叫");
// }
//}
public class Frank {
public static void main(String[] args) {
// Cat cat = new Cat();
Dog dog = new Dog();
System.out.println("狗的年龄是"+dog.age);
}
}
2.1.3.2 我想访问父类中的成员变量而不是子类中的成员变量如何访问?
1.super关键字。我们可以通过super来指定访问的这个成员变量或者方法是父类对象的!!
2.this关键字访问的是当前对象的。如果我访问的对象在子类中没有那么就会访问父类对象中有的我这个访问的这个对象。
3.super和this的区别
super.访问父类成员变量
super.访问父类的成员方法
super()访问父类的构造方法
this.访问当前对象的成员变量
this.访问当前对象的成员方法
this()访问当前对象的构造方法
(访问的顺序是最近优先原则)
4.super关键字不能出现在static方法中。因为只要有继承就会依赖对象,super不能继承构造方法。要用super()才能用。
3.子类的构造方法,如何调用父类中的构造方法
我们在父类中定义了一个构造方法我们会发现下面Dog类报错了。
1.子类继承父类以后要对成员变量进行初始化。
2.初始化的方法就是用构造方法
3.从上面代码可以看到在产生子类对象的时候,父类中的成员先初始化好(使用构造方法进行初始化)
4.那么在产生子类对象的时候就要对子类对象中的成员变量初始化才行(我们没写构造方法,java编译器会自己生成一个构造方法,也就是说只要要实例化对象就一定会有构造方法)
5.我们子类Dog的成员变量是age我们要想初始化子类Dog中的age成员变量可以这样如下代码,在下面代码中我们用子类的构造方法初始化了子类中的成员变量
父类中的成员变量自然使用父类中的构造方进行初始化。我们用父类的构造方法初始了name和 age。
记住一定是父类先用构造方法进行初始化
子类最后用构造方法进行初始化.
我们来实例化一下Dog对象。代码如下。
class Animal{
public String name ;
public int age ;
public Animal(String name, int age) {
this.name = name;
this.age = age;
}
}
class Dog extends Animal{
public String color ;
public Dog(String name, int age, String color) {
super(name, age);
this.color = color;
}
public void eat() {
System.out.println("正在吃");
}
}
//class Cat extends Animal{
// public Cat(String name, int age) {
// super(name, age);
// }
//
// public void barks() {
//
// System.out.println("正在喵喵叫");
// }
//}
public class Frank {
public static void main(String[] args) {
// Cat cat = new Cat();
Dog dog = new Dog("pencheng",21,"green on head");
System.out.println("狗的年龄是"+dog.age);
System.out.println("狗的名字是"+dog.name);
System.out.println("狗的名字是"+dog.color);
}
}
如果还是明白这个构造方法的运行过程,进行调试来进行理解!!!自己打断点!!
我们自己没写父类的构造方法和调用父类的构造方法来初始化的时候java会自己生成一个构造方法来进行初始化!!大家记住
继承一定是先父后子!!!!!!!!!!!!!!!!!!!!!!!!
子类继承完父类后里面有父类的成员变量,构造方法不能继承!!!!!!!!!!!!!!!!
在继承中在调用父类的构造方法初始化super一定要在第一行,用子类初始化子类成员变量this在super的后面,没super this就是第一行!!!!!!!(
1.super和this只能同时出现在构造函数的第一行;
2.在一个构造函数中,只能通过使用super或者this调用一个构造函数,并且只能调用一个;
3.如果调用super,那么要调用父类的构造函数,如果调用this,那么要调用本类的其他构造函数;
4.当同时出现super和this时,先执行调用的构造函数,再执行当前构造函数的其余部分。 因此,虽然super和this可以同时出现在同一个构造函数中,但是使用时需要仔细考虑代码逻辑,以避免出现错误。
)
4.调用顺序
1.不管在什么情况下,静态方法最先执行(只执行一次不管父类还是子类),父类的静态方法先执行子类的后面执行后面的也是一样。然后实例化。然后构造方法。
(代码块的顺序也是一样的)
2.如果有继承关系,先执行父类的构造方法,再执行子类的构造方法。
3.静态方法不依赖于实例化的对象,可以直接通过类名调用。静态方法可以访问静态变量,但是不能访问非静态变量。非静态方法必须依赖于实例化的对象,只有实例化后才能调用。非静态方法可以访问非静态变量和静态变量。
4.静态变量是所有实例共享的,而非静态变量是每个实例独立拥有的。静态变量可以直接通过类名访问,非静态变量必须通过实例化的对象访问。5.静态变量和方法适用于整个类中的所有对象,而非静态变量和方法只适用于调用它们的对象。通常情况下,静态变量和方法应
该是与整个类相关的,而非静态变量和方法应该是与每个对象相关的。6.在多线程的环境下,静态变量或静态方法的使用需要注意线程安全性。需要实现同步机制来保证线程的安全protected 。
7.main方法是static修饰的!!!
5.protected(受保护的)关键字
1.protectd 权限是不同包的非子类不能用
2.不同包子类不能用不完全对,我们想用可以用super关键字进行调用
3.我们想要super调用的哪个protected的那个类必须是要有public修饰,要是default(默认情况)只能在当前文件夹使用就不行了记住这个细节!!
6.建议多使用private封装这对保密有更好的帮助!
6.继承的种类
1.单继承
2.多层继承
3.不同类继承同一个类
4.多继承(java不支持)!C++支持,这就引入了接口这个名词后面文章会讲解!
5.建议继承不超过三层。
7.final关键字
1.被final修饰的字符叫做常量也就是说他不能被修改。
2.如果有一个类你不想继承了你可以用final对它进行修饰。(这种类叫做密封类(代表当前类是不能够继承的))。
3.final还能修饰方法。代表当前方法不能被重写。(后面会对重写进行讲解)
8.继承和组合
1.组合是代码层次的一种实现方式。
2.继承的关系是 is a的关系 组合的关系是 a part of 或者 has a 的意思包括的意思
(老师和学生是学校的一部分)
3.组合是将类的实例作为另一个类的字段。可以理解为拼接成一个整体如汽车由轮胎,方向盘发动机等等进行组合
4.代码实现组合如下图。
class Student_1{
}
class Teacher{
}
class School{
public Student_1[]student_1s;
public Teacher[]teachers;
}
public class Frank {
public static void main(String[] args) {
}
}
学生和老师组合成了学校。