为什么需要继承?
下面这个例子中猫和狗有相同的name属性,但我们需要实现两个差不多的类,为了解决这个问题,我们可以使用继承。
class Cat{
public String name;
public void eat(){
System.out.println(name+"猫吃饭");
}
}
class Dog{
public String name;
public void eat(){
System.out.println(name+"狗吃饭");
}
}
public class 继承 {
public static void main(String[] args) {
Cat cat=new Cat();
Dog dog=new Dog();
cat.name="mi";
dog.name="i";
cat.eat();
dog.eat();
}
}
继承中,我们就可以把共同属性取出来。
class A{ public String name; public void eat(){ System.out.println(name+"正在吃饭"); } } class Cat extends A{ } class Dog extends A{ } public class 继承 { public static void main(String[] args) { Cat cat=new Cat(); Dog dog=new Dog(); cat.name="mi"; dog.name="i"; cat.eat(); dog.eat(); } }
继承最大的意义是可以对代码进行复用。
我们把Dog和Cat叫子类或者派生类,把A叫父类或者基类/超类。
子类和父类是is-a的关系。
extends是 继承关键字。
继承时修饰符可以不写。
new创建对象时,堆中也会有父类中的成员。
注意:
- 父类成员的访问
子类访问父类成员变量。
1.子类不存在父类同名变量
class A{
public int a;
}
class Sys extends A{
public int c;
public void sys(){
System.out.println(a);
}
}
public class 继承 {
public static void main(String[] args) {
Sys cat=new Sys();
cat.sys();
}
}
2.子类存在父类同名变量
如果父类和子类有同名成员变量,那么优先访问子类自己的。
但是Sys创建的对象中含有父类和子类的b。
![](https://i-blog.csdnimg.cn/blog_migrate/1a111754bb6082283a989ec15c7ea9f8.png)
super暂且理解为父类的引用。正确的理解是只是一个关键字。因为写时没有实例化父类对象。
那如果子类和父类方法重名呢?
class A{
public int a;
public int b=1;
public void test1(){
System.out.println("父类");
}
}
class Sys extends A{
public int c;
public int b=2;
public void test1(){
System.out.println("子类");
}
public void sys(){
test1();
}
}
public class 继承 {
public static void main(String[] args) {
Sys cat=new Sys();
cat.sys();
}
}
依然 是就近原则。
强制使用父类也可以用super。
如果重名,一个有参数一个没参数(构成重载),那么传参的调用有参数的,没传参的调用没参数的。
If two methods of a class (whether both declared in the same class, or both inherited by a class, or one declared and one inherited) have the same name but signatures that are not override-equivalent, then the method name is said to be overloaded.
如果一个类的两个方法(无论是在同一个类中声明的,还是由一个类继承的,或者一个声明的和一个继承的)具有相同的名称,但签名不是重写等效的,那么方法名称被称为重载。
所以重载不一定在一个类中,继承下来的名字相同的也可以是重载。
通过子类对象访问父类与子类中不同名方法时,优先在子类中找,找到则访问,否则在父类中找,找到 则访问,否则编译报错。通过派生类对象访问父类与子类同名方法时,如果父类和子类同名方法的参数列表不同 ( 重载 ) ,根据调用 方法适传递的参数选择合适的方法访问,如果没有则报错;
super注意事项:
- 子类的构造方法
下面图中,添加完父类构造函数后,子类发生了报错
因为 在继承关系上,一定先帮助父类进行构造。那么帮助父类构造只有一种路径,那就是在子类调用父类构造方法,子类构造完之前,父类需要构造完。
这样改就会了。
构造子类结束前,通过super显示调用父类构造方法,帮助父类成员进行初始化。
帮助父类构造一定要调用父类构造方法,下面这样赋值是不行的。
当然,建议下面这样写子类构造函数。这样使用时,构造会更加灵活。
先构造子类,后调用父类构造函数也不对。
super在子类调用父类构造方法时一定要放第一层。
super和this在调用构造方法时不能同时出现,因为this里面也要super调用。
下面例子中我们发现父类中构造函数注释后,子类super调用构造函数不报错,而把父类构造函数写上,子类super调用构造函数就报错了。
因为写上构造函数,父类就不自动生成默认构造方法了。
当我们写上一个构造函数后,就不报错了。
当父类和子类没有显示写任何构造方法时,父类会默认生成
Public A(){
}
子类会默认生成
Public B(){
super();
}
构造函数。
- super和this
- 再谈初始化
上图中程序,父类优先与子类执行,静态代码块最先执行,静态代码块只执行一次。
对象创建时执行实例代码块。实例代码块执行后,执行构造方法。
private修饰的成员变量或者成员方法只能在当前类中使用,类外不能使用,继承后子类不能调用,
如果什么都不写,那么是包访问权限,指的是只能在当前包中使用。
public修饰意味在哪里都能访问。
这叫一个包。
下面这个例子是同一个包中的同一个类。
package demo2;
public class test1{
protected int a;
public static void main(String[] args) {
test1 ji=new test1();
ji.a=1;
System.out.println(ji.a);
}
}
我们发现,test2中没有定义a,但能调用test1中的a。
而下面展示的就是不同包的子类,其中a是test1中被protected修饰的成员变量。
而从上面表格中我们看到,被protected修饰的成员变量在不同包的子类中可以被访问,
这里是因为不能通过引用去访问,而想要super去访问。
下面这样使用就可以了。
package demo;
import demo2.test1;
public class test3 extends test1 {
public void superp(){
super.a=1;
System.out.println(super.a);
}
public static void main(String[] args) {
test1 ji=new test1();
// super.a=1;
}
}
然后我们可以通过定义test3对象,来调用superp,不能直接调用superp(),因为需要静态修饰。
注意静态方法中不能使用super
注意上述例子有一个基本点是test1必须是public修饰的。
那么继承中被 private修饰的成员是否被继承了呢?
答案是被继承了,但是不能访问。
权限大小:private<默认<protected<public
注意:继承深度最好不要太深。
一个类加上final后,就不能被继承了。此时test1叫密封类。
被final修饰的变量是个常量。常量一般大写。
成员变量被final修饰一定要赋初值。
下面例子中第一个是错的,被final修饰的a意味着a的值不能改变,而a存的是对象的地址。
而a[0]是改变这个地址的值,所以可以改变。
- 组合
组合是代码的一种实现方式。是一种设计思想。
a part of 或者has a的关系设计为组合。
class Teacher{}
class Student {
}
class School{
public Teacher[] teacher=new Teacher[3];
public Student[] student=new Student[3];
}
public class 继承 {
public static void main(String[] args) {
School school=new School();
}
}
Teacher和Student的对象不在School对象中,他们是单独的。
School只存了teacher和student这两个引用。
下图中,上面是定义引用了数组,里面存对象地址,没定义对象,而下面才是定义变量。