面相对象思想中提出了继承的概念,专门用来进行共性抽取,实现代码复用。
子类将父类的一些属性与方法继承过来,然后自己再添加一些新的特性。
1:在Java中如果要表示类之间的继承关系,需要借助extends关键字
2:继承的是:除了父类的构造方法外的所有。
3:单继承:一个子类只能继承一个父类,不可能继承2个或多个类。
4: 子类继承父类中的除构造方法外的所有东西,但是父类中的private修饰的方法和字段,
在子类中是无法被访问的。
public class Dog extends Animal{
void bark(){
System.out.println(name + "汪汪汪~~~");
}
}
public class Base {
int a;
int b;
}
public class Derived extends Base{
int c;
public void method(){
a = 10; // 访问从父类中继承下来的a
b = 20; // 访问从父类中继承下来的b
c = 30; // 访问子类自己的c
}
}
public class Base {
int a;
int b;
int c;
}
/
public class Derived extends Base{
int a; // 与父类中成员a同名,且类型相同
char b; // 与父类中成员b同名,但类型不同
public void method(){
a = 100; // 访问父类继承的a,还是子类自己新增的a?
b = 101; // 访问父类继承的b,还是子类自己新增的b?
c = 102; // 子类没有c,访问的肯定是从父类继承下来的c
}
}
在子类方法中 或者 通过子类对象访问成员时
如果访问的成员变量子类中有,优先访问自己的成员变量
如果访问的成员变量与父类中成员变量同名,则优先访问自己的.
成员变量访问遵循就近原则,自己有优先自己的,如果没有则向父类中找。
public class Base {
public void methodA(){
System.out.println("Base中的methodA()");
}
}
public class Derived extends Base{
public void methodB(){
System.out.println("Derived中的methodB()方法");
}
public void methodC(){
methodB(); // 访问子类自己的methodB()
methodA(); // 访问父类继承的methodA()
}
}
成员方法没有同名时,在子类方法中或者通过子类对象访问方法时,则优先访问自己的,自己没有时 再到父类中找,如果父类中也没有则报错。
public class Base {
public void methodA(){
System.out.println("Base中的methodA()");
}
public void methodB(){
System.out.println("Base中的methodB()");
}
}
public class Derived extends Base{
public void methodA(int a) {
System.out.println("Derived中的method(int)方法");
}
public void methodB(){
System.out.println("Derived中的methodB()方法");
}
public void methodC(){
methodA(); // 没有传参,访问父类中的methodA()
methodA(20); // 传递int参数,访问子类中的methodA(int)
methodB(); // 直接访问,则永远访问到的都是子类中的methodB(),基类的无法访问到
}
}
(1):通过子类对象访问父类与子类中不同名方法时,优先在子类中找,找到则访问,否则在父类中找,找到 则访问,否则编译报错
(2):通过派生类对象访问父类与子类同名方法时,如果父类和子类同名方法的参数列表不同(重载),根据调用 方法适传递的参数选择合适的方法访问,如果没有则报错;如果父类和子类同名方法的原型一致(重写-后 面讲),则只能访问到子类的,父类的无法通过派生类对象直接访问到。
子类和父类中可能会存在相同名称的成员,如果要在子类方法中访问父类同名成 员时,该如何操作?直接访
问是无法做到的,Java提供了super关键字,该关键字主要作用:在子类方法中访问父 类的成员(字段和方法)。
public class Base {
int a;
int b;
public void methodA(){
System.out.println("Base中的methodA()");
}
public void methodB(){
System.out.println("Base中的methodB()");
}
}
public class Derived extends Base{
int a; // 与父类中成员变量同名且类型相同
char b; // 与父类中成员变量同名但类型不同
// 与父类中methodA()构成重载
public void methodA(int a) {
System.out.println("Derived中的method()方法");
}
// 与基类中methodB()构成重写(即原型一致,重写后序详细介绍)
public void methodB(){
System.out.println("Derived中的methodB()方法");
}
public void methodC(){
// 对于同名的成员变量,直接访问时,访问的都是子类的
a = 100; // 等价于: this.a = 100;
b = 101; // 等价于: this.b = 101;
// 注意:this是当前对象的引用
// 访问父类的成员变量时,需要借助super关键字
// super是获取到子类对象中从基类继承下来的部分
super.a = 200;
super.b = 201;
// 父类和子类中构成重载的方法,直接可以通过参数列表区分清访问父类还是子类方法
methodA(); // 没有传参,访问父类中的methodA()
methodA(20); // 传递int参数,访问子类中的methodA(int)
// 如果在子类中要访问重写的基类方法,则需要借助super关键字
methodB(); // 直接访问,则永远访问到的都是子类中的methodA(),基类的无法访问到
super.methodB(); // 访问基类的methodB()
}
}
注意:
1:只能在非静态方法中使用
2: 在子类方法中,访问父类的成员变量和方法。
子类对象构造时,需要先调用基类构造方法,然后执行子类的构造方法
public class Base {
public Base(){
System.out.println("Base()");
}
}
public class Derived extends Base{
public Derived(){
// super(); // 注意子类构造方法中默认会调用基类的无参构造方法:super(),
// 用户没有写时,编译器会自动添加,而且super()必须是子类构造方法中第一条语句,
// 并且只能出现一次
System.out.println("Derived()");
}
}
public class Test {
public static void main(String[] args) {
Derived d = new Derived();
}
}
结果打印:
Base()
Derived()
在子类构造方法中,并没有写任何关于基类构造的代码,但是在构造子类对象时,先执行基类的构造方法,然后执 行子类的构造方法,因为:子类对象中成员是有两部分组成的,基类继承下来的以及子类新增加的部分 。父子父子 肯定是先有父再有子,所以在构造子类对象时候 ,先要调用基类的构造方法,将从基类继承下来的成员构造完整 ,然后再调用子类自己的构造方法,将子类自己新增加的成员初始化完整 。
注意:
1: 若父类显式定义无参或者默认的构造方法,在子类构造方法第一行默认有隐含的super()调用,即调用基类构 造方法。
2: 如果父类构造方法是带有参数的,此时编译器不会再给子类生成默认的构造方法,此时需要用户为子类显式 定义构造方法,并在子类构造方法中选择合适的父类构造方法调用,否则编译失败。//实践
3:在子类构造方法中,super(…)调用父类构造时,必须是子类构造函数中第一条语句。
4: super(…)只能在子类构造方法中出现一次,并且不能和this同时出现
1: 只能在类的非静态方法中使用,用来访问非静态成员方法和字段
2: 在构造方法中调用时,必须是构造方法中的第一条语句,并且不能同时存在。
1: this是当前对象的引用,当前对象即调用实例方法的对象,super相当于是子类对象中从父类继承下来部分成员的引用
2:在非静态成员方法中,this用来访问本类的方法和属性,super用来访问父类继承下来的方法和属性
3: this是非静态成员方法的一个隐藏参数,super不是隐藏的参数
4:在构造方法中:this(…)用于调用本类构造方法,super(…)用于调用父类构造方法,两种调用不能同时在构造 方法中出现
为了实现封装特性,Java中引入了访问限定符,主要限定:类或者类中成员能否在类外或者其 他包中被访问。
// 为了掩饰基类中不同访问权限在子类中的可见性,为了简单类B中就不设置成员方法了
// extend01包中
public class B {
private int a;
protected int b;
public int c;
int d;
}
// extend01包中
// 同一个包中的子类
public class D extends B{
public void method(){
// super.a = 10; // 编译报错,父类private成员在相同包子类中不可见
super.b = 20; // 父类中protected成员在相同包子类中可以直接访问
super.c = 30; // 父类中public成员在相同包子类中可以直接访问
super.d = 40; // 父类中默认访问权限修饰的成员在相同包子类中可以直接访问
}
}
// extend02包中
// 不同包中的子类
public class C extends B {
public void method(){
// super.a = 10; // 编译报错,父类中private成员在不同包子类中不可见
super.b = 20; // 父类中protected修饰的成员在不同包子类中可以直接访问
super.c = 30; // 父类中public修饰的成员在不同包子类中可以直接访问
//super.d = 40; // 父类中默认访问权限修饰的成员在不同包子类中不能直接访问
}
}
// extend02包中
// 不同包中的类
public class TestC {
public static void main(String[] args) {
C c = new C();
c.method();
// System.out.println(c.a); // 编译报错,父类中private成员在不同包其他类中不可见
// System.out.println(c.b); // 父类中protected成员在不同包其他类中不能直接访问
System.out.println(c.c); // 父类中public成员在不同包其他类中可以直接访问
// System.out.println(c.d); // 父类中默认访问权限修饰的成员在不同包其他类中不能直接访问
}
}
1: Test C 是一个普通的类,不是子类,也不是父类。
2: j a v a中有很多的类,每个类中又有2个东西:字段(成员变量)和方法。
字段:不是方法的都是字段。
3:方法(不管是不是静态的方法)里面可以创建对象,方法里面可以干大多数想干的事。
4:如果没有加访问修饰限定符,那默认的是包访问权限,只能在同一个包中进行访问。
class anmail{
public String name;
public int age;
public void jihe(){
System.out.println(this.name+" "+this.age+" "+"eat!");
}
public anmail(String name){
this.name=name;
}
public anmail(int age){
this.age=age;
}
}
class dog extends anmail {
public int a;
public dog(int a){
super(a);//相当与anmail(a)
}
/*
重点:
public dog(int a){
super(this.a);
//因为本类当中的a还没有初始化。
}
这样写是错误的。
例子看下面的图片
*/
public void func(int x) {
this.a = x;
}
}
public class Text15 {
public static void main(String[] args) {
bird bird1=new bird("鸟");
bird1.age=12;
dog dog1=new dog(10);
dog1.func(10);
dog1.name="牛仔";
bird1.jihe() ;
dog1.jihe();
}
}
执行逻辑:
编译器通过public找到Z类;然后找到Z类中的main方法;然后创建了一个Z对象,然后调用Z的构造方法;
从而进入Z的构造方法,因为Z继承了X ,所以Z是X的子类,所以要先进行构造父类,
其实public Z(super())里面有一个隐藏的super
{
}
现在要进行构造父类X,在进行X构造的时候,先构造(初始化)X的成员变量,再构造(初始化)X的代码块,最后构造(初始化)X的构造方法。
所以先进行y对象的创建,然后调用Y的构造方法;同样在进行Y构造的时候,先构造(初始化)Y的成员变量,再构造(初始化)Y的代码块,最后构造(初始化)Y的构造方法。
所以打印Y后回到类X打印X,回到Z的构造方法,同样在进行Z构造的时候,先构造(初始化)Z的成员变量,再构造(初始化)Z的代码块,最后构造(初始化)Z的构造方法。所以先打印Y再打印Z。
即打印:YXYZ
private 修饰的成员,只能被在同一个包中,同一个类下创建的对象访问。
//例如:在Animal类中有一个private修饰的成员,其只能在Animal类中创建的以Animal为模板的对象中访问。
1:一个包中有很多的类,编译器会自动的从public修饰的类中寻找main方法,如果没有找到的话就去其他的类寻找。
2:类的方法中只能调用其他方法,不可以声明实例一个方法
3:main方法是一个static修饰的方法,他不可以访问非静态的方法与变量
4:在方法里面可以创建一个对象,在方法外面类里面也可以创建一个对象。
5:在静态的方法中,访问非静态的变量和方法时,需要对象的引用。
例如:
public class Shut extends Animal {
public static void method(Shut shut1){
System.out.println(shut1.name);//对象的引用
}
public static void main(String[] args) {
Shut shut1=new Shut();
method(shut1);
shut1.name="111";
shut1.age=10;
}
}
继承的方式:
一般我们不希望出现超过三层的继承关系
如果想从语法上进行限制继承, 就可以使用 final 关键字
shut1.name="111";
shut1.age=10;
}
一般我们不希望出现超过三层的继承关系
如果想从语法上进行限制继承, 就可以使用 final 关键字
少年的肩应该担起草长莺飞和清风明月, 女孩的眼应该藏下星辰大海和万丈光芒。