继承:
当一个类继承了另一个类,另外一个类中所有的属性和方法子类就天然具备了。
JAVA中使用 extends 表示类的继承。
public class Animal {
public String name;
public void eat(String food) {
System.out.println(this.name + "正在吃" + food);
}
}
public class Dog extends Animal{
}
public class Test {
public static void main(String[] args) {
Animal animal = new Animal();
animal.name = "动物";
animal.eat("食物");
Dog dog = new Dog();
dog.name = "七七";
dog.eat("狗粮");
}
}
继承的规则:
a.要能使用继承,前提必须满足类之间的存在父子关系
b.一个子类只能使用extends继承—个父类。(单继承)
Java中不允许多重继承。extends后面只能跟一个父类,不允许多层继承,没法当儿子,可以当孙子。
e.g. Taidi 继承 Dog,而 Dog 继承 Animal ,则 Taidi 也有 Animal 的属性和方法。
c.子类会继承父类的所有属性和方法,其中又分为:
①显示继承(public属性和方法可以直接使用)
public class Dog extends Animal{
}
②隐式继承(private属性和方法),子类其实也继承了这个属性和方法,但是无法直接使用。
age这个属性只是在当前类的内部可见,子类其实继承了,但是没办法直接调用,需要通过构造方法。
public class Animal {
// age这个属性只是在当前类的内部可见,子类其实继承了,但是没办法直接调用。
private int age;
public void setAge(int age) {
this.age = age;
}
public int getAge() {
return age;
}
}
public class Test {
public static void main(String[] args) {
Dog dog = new Dog();
dog.setAge(10);
System.out.println(dog.getAge());
}
子类没法直接使用该属性,必须通过父类提供的方法来操作。
关于继承中的静态方法和属性
静态方法和属性是归于类所有的,当一个类继承另一个类时,所有的静态方法和属性就会继承,但是能否直接使用还是要看权限。区别仅限于是到底是通过子类对象来使用还是直接通过类名称来使用。
关于protected在继承中的访问权限
protected指的是不同包的具有继承关系的类的内部可见的。出了这个protected修饰的类就不能用。
public class Animal {
// 当前类和子类可见,没有继承关系的类不可见
protected String name = "七七";
}
package person;
import animal.Animal;
public class Person extends Animal {
public void fun(){
//name属性是protected权限,因此在子类Person中可以直接使用。
System.out.println(name);
}
}
package animal;
import person.Person;
public class Test {
public static void main(String[] args) {
Person person = new Person();
person.fun();
}
}
Test不是Animal的子类且不在一个包中因此name对于Test类来说不可见的
Person类继承了Animal类,name这个属性在当前类中可见的。Test这个类和Animal这个类没有任何关系,但是Test和Animal是同一个包,因此Testt可使用name属性。不包含子包,包含是指同级目录。
特别需要注意的一个点!!!!
如果有和子类(Person)在同一个包下的类(Test)调用了 子类(Person),那么 Test 类并不能使用 子类(Person)的父类 Animal 中的属性和方法!
因为 protected 权限范围只在当前类(Animal )和子类(Person)的内部可见,换句话说虽然子类(Person)有权限,但是 Test 类并没有权限。
一道面试题
请写出以下代码输出顺序
package animal;
public class B {
public B() {
System.out.println("1.B的构造方法---------------");
}
{
System.out.println("2.B的构造块-----------------");
}
static {
System.out.println("3.B的静态块-----------------");
}
}
package animal;
public class D extends B{
public D() {
System.out.println("4.D的构造方法--------------");
}
{
System.out.println("5.D的构造块----------------");
}
static {
System.out.println("6.D的静态块----------------");
}
public static void main(String[] args) {
System.out.println("7.main开始。。。。");
new D();
new D();
System.out.println("8.main结束。。。。");
}
}
思路:
由于main存在于D子类中,若JVM要调用main,首先要加载主类,加载主类,执行主类的静态块,又因为D继承了B,先加载父类才加载子类,所以
① 3 (父类的静态块) --> 6(子类的静态块)
② 类加载结束后,进入主方法 执行 --> 7
产生子类对象,先要产生父类对象,先调用构造块,下来才是构造方法;
③ 先调用父类的构造块 -->2,
④ 调用父类构造方法 -->1
⑤ 父类对象产生完毕,接下来是子类构造块 -->5
⑥ 子类构造方法 -->4,子类对象产生完毕
第二个 new 实例化 上面的 ③到⑥ 再走一遍即可
⑦ -->2-->1 -->5-->4
⑧ 最后执行 -->8
即 3 --> 6 --> 7 --> 2 --> 1 --> 5 --> 4 --> 2 --> 1 --> 5 --> 4 --> 8
答案:
super关键字
修饰属性
super先从直接父类中寻找同名属性,若不存在再向上寻找,但是如果在父类中找到但是没有权限拿到属性,就不会再向上找。
this直接从当前类中找同名属性,若不存在再向上搜索。
修饰方法
修饰构造方法
①当产生子类对象时,默认先产生父类对象,若父类对象还有继承,继续向上先产生祖类对象。
②super直接父类无参构造可以省略。但是若父类中不存在无参构造,则子类构造方法的首行必须使用super(有参构造)。这就有一个点就是在一个构造方法中无法同时显示使用this()和 super(),因为都要再第一行。但却可以同时使用,因为构造方法首行会默认调用super()。
修饰普通方法
直接从父类中寻找同名方法
super不能指代当前父类的对象引用。这一点和 this 相反。