java 之 继承


1、继承的描述:
	通过 extends 关键字让类与类之间产生关系。
	多个类具有相同的属性或者行为时,将这些内容抽取到单独一个类中,那么多个类不必再
	定义这些属性和行为,只要继承哪个类即可。多个类成为子类,单独的类成为父类或者超类。

    PS: 1 子类可以访问父类中非私有的属性和行为
        2 子类无法继承父类中私有的内容
        3 父类怎么来的?共性不断向上抽取来的

    继承的好处:
        1 继承的出现提高了代码的复用性
        2 继承的出现让类与类之间产生了关系,提供了多态的前提

2、继承的特点
    
    java 类只支持单继承,不支持多继承。因此一个类只有一个父类,不能有多个

    原因:当出现多继承时,父类中出现相同的方法名时,子类要执行哪一个方法是不确定。

3、 super 和 this关键字
    1 成员变量
        this 和 super 的用法很相似,this 代表本类对象的引用;super 代表父类的内存空间的标识
        当本类成员和局部变量同名时,用 this区分;
        当子父类中出现同名成员变量时,用 super区分父类
        ————————————————————————————————————————————————————————————————————
                class Fu{
                    private int num = 4;
                    public int getNum(){
                        return num;
                    }
                }
                class Zi extends Fu{
                    private int num = 3;
                    void show(){
                        System.out.println("this.num:"+this.num+"...super.num:"+super.num);
                    }
                }
                class ExtendsDemo{
                    new Zi().show();
                }
                输出结果: this.num:3...super.num:4
        ————————————————————————————————————————————————————————————————————
    2 成员函数
        当子父类中出现成员函数一模一样去情况,会运行子类的函数
        这种现象,称为覆盖操作,这是函数在子父类中的特性。
        在子类覆盖方法中,要继续使用被覆盖的方法可以通过super.函数名 获取。

        函数的两个特性:
            1 重载,在同一个类中。函数名相同,参数列表不同 overload
            2 覆盖,在子类中,覆盖也成为重写,覆写,override

        何时使用重写操作?
            当子类需要父类的功能,但子类的功能主体有子集独特的内容时,可以复写父类的方法,
        这样既沿袭了父类的功能,又定义了子类特有的内容。

        PS: 1 父类中私有方法不能被覆盖(子类看不到)
            2 父类的 static 方法无法覆盖
            3 覆盖时,子类方法权限一定要大于或等于父类方法的权限

    3. 构造函数
        子父类中构造函数的特点:
        在子类构造函数执行时,发现父类构造函数也运行了。
        原因:在子类的构造函数中,第一行有一个默认的隐式语句:super();
        注意:如果使用super(4);语句调用父类的其他构造函数,那么默认的父类构造函数将不会再被调用。

4、子类的实例化过程
    子类中所有的构造函数默认都会访问父类中空参数的构造函数
    因为每一个子类的构造函数第一行都有一条默认语句 super();

    为什么子类实例化的时候要访问父类中的构造函数呢?

        那是因为子类继承了父类,获取到了父类中内容(属性),所以在使用父类内容之前,要先看父类是如何对
    自己的内容进行初始化的。

    P.S.
    1 当父类中没有空参数的构造函数时,子类的构造函数必须通过this或者super语句指定要访问的构造函
    数。
       
    2 子类构造函数中如果使用this调用了本类构造函数,那么默认的super();就没有了,因为super和this都只
     能定义在第一行,所以只能有一个。 但是可以保证的是,子类中肯定会有其他的构造函数访问父类的构造函数。

    3 super语句必须要定义在子类构造函数的第一行!因为父类的初始化动作要先完成。
    ————————————————————————————————————————————————————————————————————
            class Fu{
                Fu(){
                    super();//没写时,系统会隐士的给出
                    //子类初始化时,调用的是子类的show,但此时子类特有的成员变量num 未初始化
                    show();
                }
                public void show(){
                    System.out.println("Fu show");
                }
            }
            class Zi extends Fu{
                int num = 8;
                Zi(){
                    super();
                    //通过super初始化父类内容时,此时子类的成员变量并未显示初始化,等 super父类
                    //初始化完毕后,才进行子类的成员变量显式初始化
                }
                public vois show(){
                    System.out.println("Zi show..."+num);
                }
            }
            class ExtendDemo(){
                public static void main(String[] args){
                    Zi zi = new Zi();
                    zi.show();
                }
            }
        输出结果:  Zi show...0
                    Zi show...8

        总结:Zi zi =  new Zi();的实例化过程
            1 JVM 会读取指定路径下的Zi.class 文件,并加载如内存,并会先加载Zi的父类(如果
        有直接父类)
            2 在内存开辟空间,并分配地址(父类、子类中的成员和方法同时开辟)
            3 并在对象空间中,对对象的属性进行默认初始化
            4 调用对应的构造函数进行初始化
            5 在构造函数中,第一行会先调用父类中的构造函数super()进行初始化
            6 父类构造函数初始化完毕后,再对子类的属性进行显示初始化
            7 再进行子类构造函数的特定初始化
            8 初始化完毕后,将地址值赋给引用变量
            PS:类定义中如果存在构造代码块,代码块会先于构造函数执行!!
    ————————————————————————————————————————————————————————————————————
5、 final关键字

    final可以修饰类,方法,变量
    final修饰的类不可以被继承
    final修饰的方法不可以被覆盖

    final修饰的变量时一个常量,只能被赋值一次

    为什么要用final修饰变量,其实,在程序中如果一个数据是固定的。 那么直接使用这个数据就可以了,但是
        这种阅读性差,所以应该给数据起个名称。 而且这个变量名称的值不能变化,所以加上final固定。
    写法规范:常量所有字母都大写,多个单词,中间用_连接。

6、抽象类
    
    抽象定义:抽象就是从多个事物中将共性的、本质的内容提取出来。
    例如:狼和狗都是犬科,犬科就是抽象出来的概念。

    抽像类:
        Java中可以定义没有方法体的方法,该方法的具体实现由子类完成,该方法称为抽象方法,包含抽象方法的
    类就是抽象类。但是抽象类不一定包含抽象方法。

    抽象方法的由来:
        多个对象都具备相同的功能,但是功能具体内容有所不同,那么在抽取过程中,只抽取了功能定义,并未抽
    取功能主体,那么只有功能声明,没有功能主体的方法称为抽象方法。
        例如:狼和狗都有吼叫的方法,可是吼叫内容是不一样的。 所以抽象出来的犬科虽然有吼叫功能,但是并不
    明确吼叫的细节。

7、抽象类的特点:
    抽象类和抽象方法必须用 abstract 关键字修饰

    抽象方法只有方法声明,没有方法体,定义在抽象类中
    格式: 修饰符 abstract 返回值类型 函数名(参数列表)

    抽象类不可以被实例化,也就是不可以用new创建对象。

    1. 抽象类是具体事物抽取出来的,本身是不具体的,没有对应的实例。 例如:犬科是一个抽象的概念,真正
存在的是狼和狗。
    2. 而且抽象类即使创建了对象,调用抽象方法也没有意义。
    3. 抽象类通过其子类实例化,而子类需要覆盖掉抽象类中所有的抽象方法后才可以创建对象,否则该子类也
是抽象类。

8、抽象类的相关问题
    1 抽象类是否有构造函数?
    答:有,用于给子类对象进行初始化

    2 抽象关键字 abstract 不可以和哪些关键字共存?
    答:private final (有冲突,编译失败)、static(无意义)

    3 抽象类中可不可以没有抽象方法?
    答:可以,但很少见。目的就是不让该类创建对象,awt的适配器对象就是这种类。
    通常这个类中的方法有方法体,但是却没有内容。

    4 抽象类和一般类的区别?
    答:
    相同点:抽象类和一般类都是用来描述事物的,都在内部定义了成员

    不同点:1 一般类有足够的信息描述事物
            抽象类描述事物的信息有可能不足。

            2 一般类不能定义抽象方法,只能定义非抽象方法
            抽象类既可以定义抽象方法,同时也可以定义非抽象方法

            3 一般类可以实例化
            抽象类不可以实例化

    5 抽象类一定是一个父类吗?
    答:是的,因为需要子类覆盖其方法才可以对子类进行实例化。

9、接口:当一个抽象类中的方法都是抽象的时候,这时可以将该抽象类用另一种形式定义和表示,就是接口
    格式: interface{}

    接口中成员的修饰符是固定的:
    成员变量:public static final  (只能是常量)
    成员方法:public abstract
     由此可知,接口中的成员都是公共的权限

    接口是对外暴露的规则
    接口是程序功能的拓展

    P.S.
    1 虽然抽象类中的全局变量和抽象方法的修饰符都可以不用写,但是这样阅读性很差。 所以,最好写上。
    2 类与类之间是继承关系,类与接口之间是实现关系。
    3 接口不可以实例化,能由实现了接口并覆盖了接口中所有的抽象方法的子类实例化。 否则,这个子类就是
    一个抽象类

    接口的出现将“ 多继承” 通过另一种形式体现出来,即“ 多实现” 。
    在java中不直接支持多继承,因为会出现调用的不确定性。
    所以,java将多继承机制进行改良,在java中变成了多实现,一个类可以实现多个接口。
    接口的出现避免了单继承的局限性。

    一个类在继承另一个类的同时,还可以实现多个接口。
            interface A{
                public abstract void show();//接口中方法没有实体
            }
            interface B{
                public abstract void show1();//抽象方法没有实体
            }
            class C{
                public void method(){};
            }
            class D extends  C implements A,B{
                public abstract void show(){} //重写接口中的方法
                public abstract void show1(){}//重写接口的方法
            }
10、抽象类和接口的异同点
    相同点:都是不断向上抽取而来的

    不同点: 1 抽象类需要被继承,而且只能单继承
                接口需要被实现,而且是多实现

             2 抽象类中可以定义抽象方法和非抽象方法,子类继承后,可以直接使用非抽象方法
                接口中只能定义抽象方法,必须由子类实现

             3 抽象类的继承,是 is a关系,定义该体系的基本共性内容
                接口的实现是 like a 关系,是拓展功能
11、多态
	定义:某一类事物的多种存在形态多态性简单说就是一个对象对应着不同类型。
	体现:
		父类或者接口的引用指向或者接收自己的子类对象。
	作用:
		多态的存在提高了程序的扩展性和后期可维护性。
	前提:
		1. 需要存在继承或者实现关系。
		2. 需要有覆盖操作。
	好处:
		提高了代码的扩展性,前期定义的代码可以使用后期的内容。
	弊端:
		前期定义的内容不能使用(调用)后期子类的特有内容。
	多态时,成员的特点:
	1. 成员变量
		编译时:参考引用型变量所属的类中是否有调用的成员变量。 有,编译通过,没有,编译失败。
		运行时:参考引用型变量所属的类中是否有调用的成员变量,并运行该所属类中的成员变量。
		简单说:编译和运行都参考等号的左边。
	2. 成员函数(非静态)
		编译时:参考引用型变量所属的类中是否有调用的函数。 有,编译通过。 没有,编译失败。
		运行时:参考的是对象所属的类中是否有调用的函数。
		简单说:编译看左边,运行看右边。
	3. 静态函数
		编译时:参考的是对象所属的类中是否有调用的函数。
		运行时:参考的是对象所属的类中是否有调用的函数。
		简单说:编译和运行看左边。
	————————————————————————————————————————————————————————————————————
		//多态
			public class Test {
				public static void main(String[] args) {
					Fu f = new Zi();//多台,父类引用指向子类的实例
					System.out.println("f.num = " +f.num);//多态引用的变量是父类的
			//		System.out.println("((Zi)f).num = "+((Zi)f).num);//强转后,子类的变量可见
					f.method();//调用的还是子类的方法
					f.show();//静态方法调用 的父类
					f.method1();//错误,子类特有的方法,父类引用不可见
				}
			}
			class Fu{
				int num = 3;
				public void method(){
					System.out.println("Fu method");
				}
				public static void show(){
					System.out.println("Fu static show");
				}
			}
			class Zi extends Fu{
				int num = 8;
				public void method(){
					System.out.println("Zi method");
				}
				public static void show(){
					System.out.println("Zi static show");
				}
				public static void method1(){
					System.out.println("Zi method1");
				}
			}

			输出:
			f.num = 3
			Zi method
			Fu static show
		————————————————————————————————————————————————————————————————————
12、内部类
		定义:
			将一个类定义在另一个类内部,里面的那个类就成为内部类。
		访问特点:
			内部类可以直接访问外部类中的成员,包括私有成员
			外部类要访问内部类的成员必须建立内部类的对象
		内部类的位置:
			内部类定义在成员位置上,可以被private、 static成员修饰符修饰。 被static修饰的内部类只能访问外部类中
			的静态成员。
			
			如果内部类是静态的,内部类成员也是静态的,可以不用创建内部类对象,直接调用。
			事实上,内部类含有静态成员时,内部类必须声明为静态类
		————————————————————————————————————————————————————————————————————
				 class InnerDemo{
					public static void main(String[] args) {
						new Outer().new Inner1().show();
						Outer.Inner.show();//内部类为静态,且成员也是静态时,可直接通过类名访问
					}
				}
				class Outer{
					private int num = 8;
					private static String str = "Outer static argument";
					public void show(){
						System.out.println("Outer show()");
					}
					class Inner1{ //内部类
						public void show(){
							System.out.println("Inner1 show(),num = "+num+".."+str);
						}public
					}
					static class Inner{ //有静态成员时,必须声明为静态类
						public static void show(){
							System.out.println("Inner static show(),num = "+str);
						}
					}
				}
				输出结果:
				Inner1 show(),num = 8..Outer static argument
				Inner static show(),num = Outer static argument
		————————————————————————————————————————————————————————————————————
		PS:
		1、 如果内部类中定义了静态成员,该内部类也必须是静态的
		2、 为什么内部类能直接访问外部类中的成员呢?
			那是因为内部类持有了外部类的引用,外部类名.this。
		3、 内部类定义在局部位置上,也可以直接访问外部类中的成员。
			同时可以访问所在局部中的局部变量,但必须是被final修饰的。
			加final后,局部变量变为常量,存储在常量池,生命周期不会再随方法调用结束而消失
			所以可以被访问。
		
	13、匿名内部类
		定义:
			就是内部类的简化写法。
		前提:
			内部类可以继承或实现一个外部类或者接口。
		格式:
			new 外部类名或者接口名(){覆盖类或者接口中的代码,(也可以自定义内容。 )}
		简单理解:
			就是建立一个带内容的外部类或者接口的子类匿名对象。
		什么时候使用匿名内部类呢?
			通常使用方法是接口类型参数,并且该接口中的方法不超过三个,可以将匿名内部类作为参数传递。
		好处:
			增强阅读性。
		
		//匿名内部类
			interface Inter{
				public abstract void show();
			}
			class Outer{
				public void method(){
					Inter in = new Inter(){//变量in只是引用变量,指向了一个匿名的内部类实例
						@Override
						public void show() {
							System.out.println(".... show .....");
						}
					};
					in.show();
				}
			}
			public class InnerDemo{
				public static void main(String[] args) {
					new Outer().method();
				}
			}
			//输出结果:
			//.... show .....


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值