• 类的初始化过程、super关键字与函数绑定


    一:类的初始化过程:

    1.先加载类级别的成员(静态成员变量的方法 以及 静态初始化块,这两个打印的顺序依据出现的先后顺序)
    2.再加载对象级别的成员(实例初始化块、普通成员变量的方法,打印的顺序依据出现的先后顺序)
    3.构造函数

    具体例子:
    public class ObjectInitTest {
        public ObjectInitTest() {
            System.out.println("这是构造函数alta+Insert快捷键:ObjectInitTest()");
        }
        //静态初始化块
        static{
            b=10;
            System.out.println("静态初始化块");
        }
        //实例初始化块  对实例成员变量(依赖于对象)
        {
            System.out.println("instance init block");
        }
        private int a=method1();//普通的成员变量,对象级别的
        private static int b=method2();//静态的成员是共享的,类级别的
        private int method1() {
            System.out.println("对象级别的method 1");
            return 1;
        }
        private static int method2() {
            System.out.println("静态的,类级别的method 2");
            return 2;
        }
    
        public static void main(String[] args) {
            /**
             * new ObjectInitTest()
             * 对象的产生过程
             * 1. JVM会在ObjectInitTest.class文件
             * 2. 先加载类级别的成员(静态成员变量的方法 以及 静态初始化块,这两个打印的顺序依据出现的先后顺序)
             * 3. 再加载对象级别的成员(实例初始化块、普通成员变量的方法,打印的顺序依据出现的先后顺序)
             * 4.构造函数
             */
            ObjectInitTest o=new ObjectInitTest();
        }
    }

     继承类同理:  静态>普通        基类>继承类

    先打印基类的静态方法以及静态初始化块(根据出现的先后顺序),再打印子类的静态方法及静态初始化块(先后顺序)。

    再打印基类普通的方法以及普通实例化块(先后),最后打印基类的构造函数;再打印子类的普通方法及普通实例化块(先后),最后打印子类的构造函数

    public class ObjectInitTest2 extends ObjectInitTest {
            private  static int c=method3();
            public static int method3(){
                System.out.println("这是继承类的静态方法");
                return 3;
            }
            static{
                System.out.println("继承类的静态初始化块");
            }
            private int d=method4();
            public int method4(){
                System.out.println("这是继承类的普通的成员方法");
                return 4;
            }
        {
            System.out.println("继承类的普通实例化块");
        }
            public ObjectInitTest2(){
                System.out.println("继承类的构造方法");
            }
    
        public static void main(String[] args) {
            ObjectInitTest2 o2=new ObjectInitTest2();
        }
    }

     二:super关键字  

    this关键字的两个用法:
    * 1.在构造函数中调用如 this(10),调用带int参数的其它的构造函数
    * 2.在成员方法里面访问其它成员,前面可以添加this.
    *
    * super关键字的三个用法:
    * 1.在派生类的构造函数中,调用super(10),调用基类的带int参数的构造函数
    * 2.super.func() 在派生类中,调用从基类继承来的func方法
    * 3.super.a 在派生类中,调用从基类继承来的名字叫a的成员变量
    *
    * this和super关键字都和对象有关,所以在static方法中不能使用这两个关键字

     实例:

    /**
     * 描述:
     * OOP(面向对象编程)中两个类常有的关系有两种:
     * 组合关系:满足a part of... 一部分   一个类定义的对象称为另一个类的成员变量   has a..的关系
     * A类是B类的一部分,A和B就设计成组合关系,设计如下
     * class A{}
     * class B{
     *     A a;  // B组合了A对象   A是B的成员变量
     *     public B{
       *         this.a = new A():
     *     }
     * }
     *
     * 继承关系:满足  a kind of... 一种的关系    用extends继承     is a..的关系
     * A是一个已经定义的类,B是A的一种,那么设计成继承关系,如下:
     * class A{}
     * class B extends A {
     *
     * }
     *
     * OOP语言的四大特征是什么?
     * 抽象   封装    继承    多态
     *         三大特征是什么?
     *       封装    继承    多态
     * 封装/隐藏 : 通过类的访问限定符实现的   private    public
     *
     *
     * 继承的意义之一:代码的复用
     *
     * 两个类什么时候设计成继承?
     * 派生类对象的初始化过程?
     * 基类的成员在派生类中如何访问?
     * 在派生类中如何调用基类的成员?
     *
     * this关键字的两个用法:
     * 1.在构造函数中调用如 this(10),调用带int参数的其它的构造函数
     * 2.在成员方法里面访问其它成员,前面可以添加this.
     *
     * super关键字的三个用法:
     * 1.在派生类的构造函数中,调用super(10),调用基类的带int参数的构造函数
     * 2.super.func() 在派生类中,调用从基类继承来的func方法
     * 3.super.a 在派生类中,调用从基类继承来的名字叫a的成员变量
     *
     * this和super关键字都和对象有关,所以在static方法中不能使用这两个关键字
     *
     * private和protected的区别?
     * 1.它们两个修饰的成员,在类的外部都不能访问
     * 2.基类的private成员,在派生类中无法访问;基类的protected成员,在派生类中可以访问
     * @Author hui
     * @Date 2019/10/15
     */
    public class DeriveTest {
        public static void main(String[] args) {
           // A a=new A();
            B b=new B(6);
            b.show();
        }
    }
    class A{
        protected int a;
        static {
            System.out.println("A的静态块");
        }
        {
            System.out.println("A的实例化块");
        }
        public A(){
            System.out.println("A的无参数构造函数");
            this.a=0;
        }
        public A(int a){
            System.out.println("A的int参数的构造方法");
            this.a=a;
        }
        public void show(){
            System.out.println("A.show is a:"+a);
        }
    }
    /**
     * 派生类B有两部分
     * 1.从基类继承来的成员
     * 2.自己定义的成员
     *
     * super()和this()都必须写在第一行
     */
    class B extends  A{
      private int a;
      private int b;
      public B(int data){
          super(4);//将4传给基类的a
          this.a=data;//给B的a进行初始化赋
          System.out.println("B的带参数的构造函数int(data)");
      }
      static {
          System.out.println("派生类B的静态块");
      }
        {
            System.out.println("B的实例化方法");
        }
        //重写父类的方法,打印基类与自己的a变量
        public void show(){
            System.out.println("A.show a is:"+super.a);
            System.out.println("B.show is a:"+a);
        }
        //调用基类的方法super关键字
        void testShow2(){
          super.show();
        }
    
    }

     

     

    三:函数的动态绑定

    实例:

    /**
     * 函数的静态绑定和动态绑定是什么?
     * 绑定(函数调用)
     * invokestatic指令就是在以静态绑定的方法,调用函数
     * invokevirtual指令就是在以动态绑定的方法,调用函数
     *
     * static方法都是静态绑定调用
     * 实例方法都是动态绑定调用
     *
     * 静态绑定,指的是编译时期的绑定,编译阶段,这个方法的调用就是确定好的,永不不会再改变
     *
     * 动态绑定,指的是运行时期的绑定,就是在编译阶段,此处调用哪个函数,是不确定的,
     *
     * final的应用场景有三个:
     * 1.final int data = 10; 可以用来定义常量
     * 2.final可以修饰类称作密封类,不能再被继承
     * 3.final可以修饰类的实例方法,称作密封方法,
     *        表示该方法不能再派生类中重写(覆盖)
     */
    
    class Base{
        protected int a;
        private String str;
        private Integer data;
    
        public Base(int val){   //构造函数
            System.out.println("Base(val)");
            this.a = val;
        }
    
        public static void show(){   //静态方法
            System.out.println("static Base.show");
        }
    
    
        public void func(){   //实例化方法
            System.out.println("instance Base.func");
        }
    
        public void func(int data){  //方法的重载,在同一个类里进行
            System.out.println("instance Base.func data");
        }
    }
        /**
            * 继承结构中,基类和派生类的方法通常有两种关系:重载和重写
            * 重载:在一个类作用域中,函数名相同,参数列表不同
            * 重写:在基类和派生类中,出现返回值相同,函数名相同,参数列表也相同的实例方法
            * 重写指的是派生类方法表中,派生类提供的重写方法,把基类相应的方法的地址给重写了(覆盖了)
            */
    class E extends Base{
            //E的构造函数调用父类的构造函数
        public E(int val) {
            super(val);
            System.out.println("派生类E的构造函数");
    
        }
        //派生类重写基类的方法
        public static void show(){
            System.out.println("static E.show");
        }
    
        // 构成重写(覆盖)的关系
        public void func(){
            System.out.println("instance E.func");
        }
    }
    
    
    /*
     *基类引用,可以引用派生类对象
     *派生类引用,不可以引用基类对象
     *
     *把基类和派生类的继承结构,也经常称作从上到下的继承结构,
     *继承结构中的类型,只支持从下到上的转换,不支持从上到下的转换
     */
    public class FunctionBond {
        public static void main(String[] args) {
            E e = new E(20); // invokespecial 构造函数,调用派生类E的构造函数
            E.show(); // invokestatic 静态绑定
            e.func(); // invokevirtual 实例方法
    
            Base b = new E(20);  //动态绑定,调用派生类E的构造函数
            Base.show(); // Base.show
            b.func(); // 调用派生类的方法
    
    
    
        }
    }

    反汇编指令:javap -c 类名.class

     

    实际的调用分析:

     

     注:基类可以引用派生类对象,派生类不可以引用基类对象

    (举例:你此时需要一个人,来一个教授可以满足;但是当你需要一个教授,随便来一个人则不能满足需求)

    
    
  • 相关阅读:
    andorid 平台调用Web Service , 图片传输
    android 中在CMD中查看sqlite
    Click ListView Item跳转Activity
    C# 中几个小“陷阱”
    Xamarin 手动安装步骤+破解(最新版Xamarin V3)
    语音播报实时天气
    手动创建VS单元测试,显示代码覆盖率
    Ubuntu 12.10 配置MyEclipes 10.7环境(加破解)
    C#对象赋值出现的诡异问题,或许你也遇到过,有待你的解决
    jquery 小插件,完成“输入字段预期值的提示信息”,防html5 placeholder属性
  • 原文地址:https://www.cnblogs.com/laurarararararara/p/11676773.html
Copyright © 2020-2023  润新知